- Neue Docker-Struktur: docker/{dev,prod}/ für klare Trennung
- Entfernt: docker-compose.override.yml (problematisch)
- Hinzugefügt: ./dev.sh und ./prod.sh Scripts für einfache Bedienung
- Container-spezifische Konfigurationen in docker/{dev,prod}/*/config/
- Aktualisierte READMEs für neue Struktur
- Backend-Daten in .gitignore hinzugefügt
- Bereinigt: Veraltete Dockerfiles und Konfigurationsdateien
Jetzt: Wartungsfreundlich, keine Verwirrung zwischen Umgebungen
334 lines
13 KiB
Markdown
334 lines
13 KiB
Markdown
# Image Uploader with Multi-Upload & Slideshow
|
|
|
|
A self-hosted image uploader with multi-image upload capabilities and automatic slideshow functionality.
|
|
|
|
## Features
|
|
|
|
**Multi-Image Upload**: Upload multiple images at once with batch processing
|
|
**Drag-and-Drop Reordering**: 🆕 Admins can reorder images via intuitive drag-and-drop interface
|
|
**Slideshow Mode**: Automatic fullscreen slideshow with smooth transitions (respects custom ordering)
|
|
**Preview Image Optimization**: Automatic thumbnail generation for faster gallery loading (96-98% size reduction)
|
|
**Touch-Friendly Interface**: 🆕 Mobile-optimized drag handles and responsive design
|
|
**Admin Panel**: Dedicated moderation interface for content management and organization
|
|
**Persistent Storage**: Docker volumes ensure data persistence across restarts
|
|
**Clean UI**: Minimalist design focused on user experience
|
|
**Self-Hosted**: Complete control over your data and infrastructure
|
|
**Lightweight**: Built with modern web technologies for optimal performance
|
|
|
|
## What's New
|
|
This project extends the original [Image-Uploader by vallezw](https://github.com/vallezw/Image-Uploader) with enhanced multi-upload and slideshow capabilities.
|
|
|
|
### 🆕 Latest Features (January 2025)
|
|
- **Drag-and-Drop Image Reordering**: Admins can now reorder images using intuitive drag-and-drop
|
|
- **Touch-Friendly Interface**: Mobile-optimized controls with always-visible drag handles
|
|
- **Slideshow Integration**: Custom image order automatically applies to slideshow mode
|
|
- **Optimistic UI Updates**: Immediate visual feedback with error recovery
|
|
- **Comprehensive Admin Panel**: Dedicated moderation interface for content curation
|
|
|
|
### Core Features
|
|
- Multi-image batch upload with progress tracking
|
|
- Automatic slideshow presentation mode
|
|
- Image grouping with descriptions and metadata
|
|
- Random slideshow rotation with custom ordering support
|
|
- Keyboard navigation support (Slideshow: Space/Arrow keys, Escape to exit)
|
|
- Mobile-responsive design with touch-first interactions
|
|
|
|
## Quick Start
|
|
|
|
### Docker Deployment (Recommended)
|
|
|
|
#### Production Environment
|
|
|
|
```bash
|
|
# Start production environment
|
|
./prod.sh
|
|
|
|
# Or manually:
|
|
docker compose -f docker/prod/docker-compose.yml up -d
|
|
```
|
|
|
|
#### Development Environment
|
|
|
|
```bash
|
|
# Start development environment
|
|
./dev.sh
|
|
|
|
# Or manually:
|
|
docker compose -f docker/dev/docker-compose.yml up -d
|
|
### Access URLs
|
|
|
|
#### Production (Port 80):
|
|
- Upload Interface: `http://localhost`
|
|
- Slideshow Mode: `http://localhost/slideshow`
|
|
- Groups Overview: `http://localhost/groups`
|
|
- Admin Panel: `http://localhost/moderation` (requires authentication)
|
|
|
|
#### Development (Port 3000):
|
|
- Upload Interface: `http://localhost:3000`
|
|
- Backend API: `http://localhost:5001`
|
|
- Slideshow Mode: `http://localhost:3000/slideshow`
|
|
|
|
### Multi-Image Upload
|
|
|
|
1. Visit `http://localhost`
|
|
2. Drag & drop multiple images or click to select
|
|
3. Add an optional description for your image collection
|
|
4. Click "Upload Images" to process the batch
|
|
5. Images are automatically grouped for slideshow viewing
|
|
|
|
### Slideshow Mode
|
|
|
|
- **Automatic Access**: Navigate to `http://localhost/slideshow`
|
|
- **Features**:
|
|
- Fullscreen presentation
|
|
- 4-second display per image
|
|
- Automatic progression through all slideshow collections
|
|
- Random selection of next slideshow after completing current one
|
|
- Smooth fade transitions (0.5s)
|
|
|
|
- **Keyboard Controls**:
|
|
- **ESC**: Exit slideshow / Return to upload page
|
|
- **Spacebar / Arrow Right**: Manually advance to next image
|
|
- **Home Button**: Return to main upload interface
|
|
|
|
### Preview Image Optimization
|
|
|
|
The application automatically generates optimized preview thumbnails for all uploaded images to significantly improve gallery loading performance.
|
|
|
|
- **Automatic Generation**:
|
|
- Preview images are created automatically on server startup
|
|
- Existing images without previews are processed on-demand
|
|
- New uploads generate previews immediately during upload
|
|
|
|
- **Technical Specifications**:
|
|
- **Max Width**: 800px (maintains aspect ratio)
|
|
- **Format**: JPEG with 85% quality
|
|
- **Size Reduction**: 96-98% smaller than originals (e.g., 2076KB → 58.5KB)
|
|
- **Performance**: ~30x faster gallery loading times
|
|
|
|
- **Smart Image Loading**:
|
|
- **Galleries & Overview**: Load lightweight preview images (~50-100KB)
|
|
- **Slideshow Mode**: Uses full-resolution originals for best quality
|
|
- **Fallback**: Automatically uses originals if preview generation fails
|
|
|
|
- **Storage**:
|
|
- Originals: `backend/src/data/images/` (~2-4MB per image)
|
|
- Previews: `backend/src/data/previews/` (~50-100KB per image)
|
|
- Database: `preview_path` column stores preview filename
|
|
|
|
### Moderation Interface (Protected)
|
|
|
|
- **Access**: `http://localhost/moderation` (requires authentication)
|
|
- **Authentication**: HTTP Basic Auth (username: admin, password: set during setup)
|
|
- **Features**:
|
|
- Review pending image groups before public display
|
|
- Approve or reject submitted collections
|
|
- Delete individual images from approved groups
|
|
- View group details (title, creator, description, image count)
|
|
- Bulk moderation actions
|
|
|
|
- **Security Features**:
|
|
- Password protected access via nginx HTTP Basic Auth
|
|
- Hidden from search engines (`robots.txt` + `noindex` meta tags)
|
|
- No public links or references in main interface
|
|
|
|
### Public Overview of all approved slideshows
|
|
- **Group Management**: Navigate to `http://localhost/groups`
|
|
- Overview of all approved slideshow collections
|
|
- Launch slideshow mode from any group
|
|
- View group statistics and metadata
|
|
|
|
|
|
## Docker Structure
|
|
|
|
The application uses separate Docker configurations for development and production:
|
|
|
|
```
|
|
docker/
|
|
├── .env.backend.example # Backend environment variables documentation
|
|
├── .env.frontend.example # Frontend environment variables documentation
|
|
├── dev/ # Development environment
|
|
│ ├── docker-compose.yml # Development services configuration
|
|
│ ├── backend/
|
|
│ │ ├── config/.env # Development backend configuration
|
|
│ │ └── Dockerfile # Development backend container
|
|
│ └── frontend/
|
|
│ ├── config/.env # Development frontend configuration
|
|
│ ├── config/env.sh # Runtime configuration script
|
|
│ ├── Dockerfile # Development frontend container
|
|
│ ├── nginx.conf # Development nginx configuration
|
|
│ └── start.sh # Development startup script
|
|
└── prod/ # Production environment
|
|
├── docker-compose.yml # Production services configuration
|
|
├── backend/
|
|
│ ├── config/.env # Production backend configuration
|
|
│ └── Dockerfile # Production backend container
|
|
└── frontend/
|
|
├── config/.env # Production frontend configuration
|
|
├── config/env.sh # Runtime configuration script
|
|
├── config/htpasswd # HTTP Basic Auth credentials
|
|
├── Dockerfile # Production frontend container
|
|
└── nginx.conf # Production nginx configuration
|
|
```
|
|
|
|
### Environment Configuration
|
|
|
|
- **Development**: Uses `docker/dev/` configuration with live reloading
|
|
- **Production**: Uses `docker/prod/` configuration with optimized builds
|
|
- **Scripts**: Use `./dev.sh` or `./prod.sh` for easy deployment
|
|
|
|
## Data Structure
|
|
|
|
Data are stored in sqlite database. The structure is as follows:
|
|
``` sql
|
|
CREATE TABLE groups (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
group_id TEXT UNIQUE NOT NULL,
|
|
year INTEGER NOT NULL,
|
|
title TEXT NOT NULL,
|
|
description TEXT,
|
|
name TEXT,
|
|
upload_date DATETIME NOT NULL,
|
|
approved BOOLEAN DEFAULT FALSE,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
CREATE TABLE sqlite_sequence(name,seq);
|
|
CREATE TABLE images (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
group_id TEXT NOT NULL,
|
|
file_name TEXT NOT NULL,
|
|
original_name TEXT NOT NULL,
|
|
file_path TEXT NOT NULL,
|
|
preview_path TEXT,
|
|
upload_order INTEGER NOT NULL,
|
|
file_size INTEGER,
|
|
mime_type TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
FOREIGN KEY (group_id) REFERENCES groups(group_id) ON DELETE CASCADE
|
|
);
|
|
CREATE INDEX idx_groups_group_id ON groups(group_id);
|
|
CREATE INDEX idx_groups_year ON groups(year);
|
|
CREATE INDEX idx_groups_upload_date ON groups(upload_date);
|
|
CREATE INDEX idx_images_group_id ON images(group_id);
|
|
CREATE INDEX idx_images_upload_order ON images(upload_order);
|
|
CREATE TRIGGER update_groups_timestamp
|
|
AFTER UPDATE ON groups
|
|
FOR EACH ROW
|
|
BEGIN
|
|
UPDATE groups SET updated_at = CURRENT_TIMESTAMP WHERE id = NEW.id;
|
|
END;
|
|
```
|
|
|
|
## Architecture
|
|
### Backend (Node.js + Express)
|
|
- **Multi-upload API**: `/api/upload/batch` - Handles batch file processing
|
|
- **Groups API**: `/api/groups` - Retrieves slideshow collections
|
|
- **Preview Generation**: Automatic thumbnail creation using Sharp (800px JPEG, 85% quality)
|
|
- **File Storage**: Organized in `/upload` directory (originals) and `/data/previews` (thumbnails)
|
|
- **Database Storage**: sqlite database in `/app/src/data/db/image_uploader.db`
|
|
|
|
### Frontend (React + Material-UI)
|
|
|
|
- **Multi-Upload Interface**: Drag & drop with preview gallery
|
|
- **Progress Tracking**: Real-time upload status
|
|
- **Spacebar / Arrow Right**: Manually advance to next image
|
|
- **Slideshow Engine**: Fullscreen presentation with automatic progression
|
|
- **Responsive Design**: Mobile and desktop optimized
|
|
- **Home Button**: Return to main upload interface
|
|
|
|
|
|
### Storage Architecture
|
|
|
|
```
|
|
Docker Volume (app-data)
|
|
src
|
|
└── app
|
|
├── src
|
|
├── upload (originals, ~2-4MB each)
|
|
│ ├── ZMmHXzHbqw.jpg
|
|
│ ├── tjjnngOmXS.jpg
|
|
│ └── ...
|
|
└── data
|
|
├── previews (thumbnails, ~50-100KB each)
|
|
│ ├── ZMmHXzHbqw.jpg
|
|
│ ├── tjjnngOmXS.jpg
|
|
│ └── ...
|
|
└── db
|
|
└── image_uploader.db
|
|
|
|
```
|
|
|
|
### Hosting it with Docker
|
|
|
|
- **Frontend**: React 17, Material-UI, React Router
|
|
- **Backend**: Node.js, Express, Multer (file handling)
|
|
- **Containerization**: Docker, Docker Compose
|
|
- **Reverse Proxy**: nginx (routing & file serving)[In order to host the project you will need to create a docker-compose file. These files are combining multiple docker images to interact with each other.
|
|
- **File Upload**: Drag & drop with react-dropzone
|
|
- **Notifications**: SweetAlert2
|
|
|
|
## API Endpoints
|
|
### Upload Operations
|
|
|
|
- `POST /api/upload/batch` - Upload multiple images with description
|
|
- `GET /api/groups` - Retrieve all slideshow groups
|
|
- `GET /api/groups/:id` - Get specific slideshow group
|
|
|
|
### Moderation Operations (Protected)
|
|
|
|
- `GET /moderation/groups` - Get all groups pending moderation
|
|
- `POST /groups/:id/approve` - Approve a group for public display
|
|
- `DELETE /groups/:id` - Delete an entire group
|
|
- `DELETE /groups/:id/images/:imageId` - Delete individual image from group
|
|
|
|
### File Access
|
|
- `GET /api/upload/:filename` - Access uploaded image files (legacy, use `/api/download` instead)
|
|
- `GET /api/download/:filename` - Download original full-resolution images
|
|
- `GET /api/previews/:filename` - Access optimized preview thumbnails (~100KB, 800px width)
|
|
|
|
## Configuration
|
|
### Environment Variables
|
|
|
|
| Variable | Default | Description |
|
|
|----------|---------|-------------|
|
|
| `API_URL` | `http://localhost:5000` | Backend API endpoint |
|
|
| `CLIENT_URL` | `http://localhost` | Frontend application URL |
|
|
|
|
### Volume Configuration
|
|
- **Upload Limits**: 100MB maximum file size for batch uploads
|
|
- **Supported Formats**: JPG, JPEG, PNG, GIF, WebP
|
|
|
|
|
|
### Backup & Restore
|
|
#### Backup slideshow data
|
|
```sh
|
|
docker cp image-uploader-backend:/usr/src/app/src/data/ ./image-uploader-backup-data
|
|
```
|
|
|
|
#### Restore slideshow data
|
|
```sh
|
|
docker cp ./image-uploader-backup-data image-uploader-backend:/usr/src/app/src/data
|
|
```
|
|
|
|
## Contributing
|
|
Contributions are welcome!
|
|
This project extends the original work by [vallezw](https://github.com/vallezw/Image-Uploader).
|
|
|
|
### Development Setup
|
|
1. Fork the repository
|
|
2. Create feature branch: `git checkout -b feature/amazing-feature`
|
|
3. Commit changes: `git commit -m 'Add amazing feature'`
|
|
4. Push to branch: `git push origin feature/amazing-feature`| Field | Type | Description |#### Changing the URL
|
|
5. Open a Pull Request
|
|
|
|
## License
|
|
This project is distributed under the MIT License. See `LICENSE` for more information.
|
|
|
|
## Acknowledgments
|
|
- Original project: [Image-Uploader by vallezw](https://github.com/vallezw/Image-Uploader)
|
|
|
|
|
|
|
|
|