A robust NestJS-based file storage service for managing file uploads, retrieval, and metadata management.
- File Upload: Securely upload files with metadata support
- File Retrieval: Fetch files by ID or filename
- Metadata Management: Store and retrieve file metadata
- Reference Support: Associate files with other entities via reference types and IDs
- Plex Integration: Smart thumbnail management for Plex media items
- Parent-Level Sharing: Efficient storage with parent-level thumbnail sharing (album/show)
- Access Control: Support for public and private file visibility
- Swagger API Documentation: Interactive API documentation
- Node.js (v16+)
- PostgreSQL and a newly created database matching the name specified in the .env
- TypeScript
Create a .env file in the root directory with the following variables:
# Application
PORT=3000
# Database
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=postgres
DB_DATABASE=file_storage
# File Storage
FILE_STORAGE_PATH=./storage
# Install dependencies
npm install
# Build the application
npm run build
# Run database migrations
npm run migration:run# Development mode
npm run start:dev
# Production mode
npm run start:prod| Method | Endpoint | Description |
|---|---|---|
| POST | /files/upload |
Upload a new file |
| GET | /files/id/:id |
Get file by ID |
| GET | /files/:filename |
Get file by filename |
| GET | /files/info/id/:id |
Get file metadata by ID |
| GET | /files/info/:filename |
Get file metadata by filename |
| DELETE | /files/:id |
Delete a file |
| Method | Endpoint | Description |
|---|---|---|
| GET | /files/plex/thumbnail |
Find Plex thumbnails by media identifiers |
Once the application is running, visit http://localhost:3000/api to access the Swagger documentation.
# Using curl
curl -X POST http://localhost:3000/files/upload \
-F "file=@/path/to/file.jpg" \
-F "referenceType=product" \
-F "referenceId=123" \
-F "isPublic=true"# Using curl
curl -X POST http://localhost:3000/files/upload \
-F "file=@/path/to/thumbnail.jpg" \
-F "referenceType=plex-show" \
-F "referenceId=12345" \
-F "isPublic=true" \
-F "plexMediaType=episode" \
-F "plexRatingKey=67890" \
-F "plexParentRatingKey=54321" \
-F "plexGrandparentRatingKey=12345" \
-F "plexTitle=My Show"# Get thumbnail for a show by grandparent rating key
curl -X GET "http://localhost:3000/files/plex/thumbnail?mediaType=episode&grandparentRatingKey=12345"
# Get thumbnail for an album by parent rating key
curl -X GET "http://localhost:3000/files/plex/thumbnail?mediaType=track&parentRatingKey=67890"
# Get thumbnail for a movie by rating key
curl -X GET "http://localhost:3000/files/plex/thumbnail?mediaType=movie&ratingKey=54321"{
"id": "550e8400-e29b-41d4-a716-446655440000",
"filename": "550e8400-e29b-41d4-a716-446655440000.jpg",
"originalName": "image.jpg",
"mimeType": "image/jpeg",
"size": 24680,
"url": "/files/id/550e8400-e29b-41d4-a716-446655440000",
"plexMediaType": "episode",
"plexTitle": "My Show"
}The API intelligently manages thumbnails at the parent level to avoid duplicates:
- Movies: Individual thumbnails for each movie
- TV Shows: One thumbnail shared by all episodes in the same show
- Music: One thumbnail shared by all tracks in the same album
This approach significantly reduces storage requirements and ensures consistent thumbnails.
src/- Source codefile-storage/- File storage moduleentities/- Database entitiesfile-storage.controller.ts- API endpointsfile-storage.service.ts- Business logic
main.ts- Application entry pointapp.module.ts- Main application module
# Unit tests
npm run test