Skip to content

Commit 750e9f0

Browse files
committed
Dockerize application for deployment
1 parent 18d8b8b commit 750e9f0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+5854
-2983
lines changed

.dockerignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.git
2+
.idea
3+
.svelte-kit
4+
build
5+
data
6+
node_modules
7+
.dockerignore
8+
.env.development
9+
.env.example
10+
.gitignore
11+
.npmrc
12+
.prettierignore
13+
.prettierrc
14+
Dockerfile
15+
LICENSE
16+
README.md

.env.example

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
# Database credentials
2-
DATABASE_URL=postgresql://root:mysecretpassword@localhost:5432/snapsort
3-
POSTGRES_USER=root
4-
POSTGRES_PASSWORD=mysecretpassword
2+
DATABASE_URL="file:/app/data/db.sqlite3"
53

64
# Path to external binaries
7-
EXIFTOOL_PATH="/snap-sort/data/exiftool/exiftool.exe"
8-
FFMPEG_PATH="/snap-sort/data/ffmpeg/bin/ffmpeg.exe"
5+
EXIFTOOL_PATH="exiftool"
6+
FFMPEG_PATH="ffmpeg"
97

108
# Path to data storage
11-
FILE_UPLOAD_DIR="/snap-sort/data/uploaded-files"
12-
LIBRARY_ROOT_DIR="/snap-sort/data/library"
9+
FILE_UPLOAD_DIR="/app/data/uploaded-files"
10+
LIBRARY_ROOT_DIR="/app/library"
11+
12+
# Deployment parameters
13+
PORT=3990
14+
PROTOCOL_HEADER=x-forwarded-proto
15+
HOST_HEADER=x-forwarded-host
16+
BODY_SIZE_LIMIT=Infinity

.idea/dataSources.xml

Lines changed: 11 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/dictionaries/project.xml

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.npmcheckrc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"depcheck": {
3+
"ignoreMatches": [
4+
"npm-check",
5+
"@iconify/json",
6+
"tailwindcss",
7+
"@tailwindcss/forms",
8+
"@tailwindcss/typography",
9+
"prettier-plugin-svelte",
10+
"prettier-plugin-tailwindcss"
11+
]
12+
}
13+
}

Dockerfile

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
FROM node:22-alpine AS base
2+
ENV PNPM_HOME="/pnpm"
3+
ENV PATH="$PNPM_HOME:$PATH"
4+
RUN corepack enable
5+
WORKDIR /app
6+
COPY package.json pnpm-lock.yaml ./
7+
8+
FROM base AS prod-deps
9+
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --prod --frozen-lockfile
10+
11+
FROM base AS builder
12+
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
13+
COPY . .
14+
RUN pnpm build
15+
16+
FROM base AS production
17+
WORKDIR /app
18+
COPY .env.production .
19+
COPY --from=prod-deps /app/node_modules node_modules/
20+
# Build files generated by Sveltekit
21+
COPY --from=builder /app/build build/
22+
# DB migrations generated by Drizzle
23+
COPY --from=builder /app/drizzle drizzle/
24+
# Drizzle configuration needed for running migrations
25+
COPY --from=builder /app/drizzle-prod.config.ts .
26+
RUN apk add --no-cache ffmpeg=~6.1.2 exiftool=~13.30
27+
VOLUME /app/data
28+
VOLUME /app/library
29+
EXPOSE 3990
30+
CMD ["pnpm", "start"]

README.md

Lines changed: 106 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
# SnapSort
22

3-
A very opinionated solution for a personal problem of organizing a photos/videos library. SnapSort helps you organize
4-
media files (images/videos) and edit metadata.
3+
A very opinionated solution for a very personal problem of organizing a photos/videos library. SnapSort helps you
4+
(read: me) organize media files (images/videos) and edit metadata.
5+
6+
## Table of Contents
7+
8+
- [Features](#features)
9+
- [Metadata Management](#metadata-management)
10+
- [Library Organization](#library-organization)
11+
- [Setup and Usage](#setup-and-usage)
12+
- [Contribution and Development](#contribution-and-development)
13+
- [Running a development instance](#running-a-development-instance)
14+
- [Project structure](#project-structure)
15+
- [Future Improvements](#future-improvements)
516

617
## Features
718

@@ -19,7 +30,9 @@ media files (images/videos) and edit metadata.
1930
Media library is organized in a "Year / Month / Day" hierarchy. The Day folder may have a `- Keyword` suffix
2031
depending on whether any of the files within that folder contains a keyword which can be used as a folder label.
2132

22-
The files follow the following naming convention: `TYPE-YYYYMMDD-INDEX`
33+
The files use the following naming convention: `TAG-YYYYMMDD-INDEX`<br/>
34+
`TAG` will be `IMG` or `VID` depending on the type of the media. A special keyword `Edit` can be added to the file to
35+
overwrite `TAG` to be `EDT`.
2336

2437
```
2538
library/
@@ -29,152 +42,124 @@ library/
2942
|- IMG-20250101-000.jpg
3043
|- VID-20250101-000.mp4
3144
|- 02 - Birthday/
45+
|- EDT-20250102-000.jpg
3246
|- IMG-20250102-000.jpg
3347
|- IMG-20250102-001.jpg
3448
```
3549

36-
## Prerequisites
37-
38-
- [Node.js](https://nodejs.org/) (v18 or later)
39-
- [PNPM](https://pnpm.io/) package manager
40-
- [Docker](https://www.docker.com/) and [Docker Compose](https://docs.docker.com/compose/) (for PostgreSQL database)
41-
- [ExifTool](https://exiftool.org/) (for metadata manipulation)
42-
- [FFmpeg](https://ffmpeg.org/) (for video processing)
43-
44-
## Installation
45-
46-
1. Clone the repository:
47-
48-
```bash
49-
git clone https://github.com/bhatushar/snap-sort.git
50-
cd snap-sort
51-
```
52-
53-
2. Install dependencies:
54-
55-
```bash
56-
pnpm install
57-
```
58-
59-
3. Create a `.env` file based on the provided `.env.example`:
60-
61-
```bash
62-
cp .env.example .env
63-
```
64-
65-
4. Edit the `.env` file to configure your environment:
50+
## Setup and Usage
6651

67-
- Set database credentials
68-
- Configure paths to ExifTool and FFmpeg
69-
- Set file storage directories
52+
**Prerequisites:**
7053

71-
5. Start the PostgreSQL database using Docker:
54+
- [Docker](https://www.docker.com/)
55+
- [Ability to use Docker](https://www.youtube.com/watch?v=DQdB7wFEygo)
7256

73-
```bash
74-
pnpm db:start
75-
```
57+
**Docker Compose configuration:**
7658

77-
6. Initialize the database:
78-
```bash
79-
pnpm db:push
80-
```
59+
```yaml
60+
services:
61+
snapsort:
62+
image: bhatushar/snapsort
63+
ports:
64+
- '3990:3990'
65+
volumes:
66+
- '/app-data:/app/data'
67+
- '/library:/app/library'
68+
environment:
69+
TZ: Asia/Calcutta
70+
restart: unless-stopped
71+
```
8172
82-
## Running the Application
73+
`/app-data` is where SnapSort will store its internal files like the database, user-uploaded media, and thumbnails.<br/>
74+
`/library` is where your media will go once processed by SnapSort.<br/>
8375

84-
### Development Mode
76+
Run the container with `docker compose up -d` and you should be able to access the website on `localhost:3990`.
8577

86-
Run the application in development mode:
78+
When you first launch the application, it will ask you to create a login password. SnapSort currently doesn't support
79+
multiple users.<br/>
80+
After logging in, you'll land on the homepage where you can upload new media files for processing. You can edit the date
81+
and time information, add titles to your media, tag them with keywords... Oh wait, you can't use keywords?
8782

88-
```bash
89-
pnpm dev
90-
```
83+
That's because you need to create the keywords first!<br/>
84+
Go to Settings > Manage Keywords. On the top-right, there will be an option to add keywords.<br/>
85+
Here, you can set the name of the keyword, its type/category, and whether to use it to label folders.<br/>
86+
Now you can go back and start tagging your files.
9187

92-
To make the development server accessible on your local network:
88+
Whatever changes you make will not persist until you save them. When you click the 'Save' button, you get two options:
9389

94-
```bash
95-
pnpm dev-network
96-
```
90+
1. _Apply Changes_: This will only store your changes in SnapSort's internal database. Your files will remain intact.
91+
This is useful if you want to come back in the future and revise your changes.
92+
2. _Move to Library_: This is the final step. It will apply your changes to your files and move them to the library.
9793

98-
### Production Mode
94+
## Contribution and Development
9995

100-
Build the application for production:
96+
This project is developed using the SvelteKit framework with TypeScript support. It uses a locally hosted SQLite
97+
database, and the DB connection is managed by Drizzle.<br/>
98+
Internally, it relies on [ExifTool](https://exiftool.org/) (for reading/writing metadata) and
99+
[FFmpeg](https://ffmpeg.org/) (for generating thumbnails for videos).
101100

102-
```bash
103-
pnpm build
104-
```
105-
106-
Preview the production build:
107-
108-
```bash
109-
pnpm preview
110-
```
101+
### Running a development instance
111102

112-
Run the production server:
103+
Set up the project:
113104

114105
```bash
115-
node build
106+
git clone https://github.com/bhatushar/snapsort.git
107+
cd snapsort
108+
pnpm install
116109
```
117110

118-
## Database Management
119-
120-
- Push schema changes to the database:
121-
122-
```bash
123-
pnpm db:push
124-
```
125-
126-
- Create migrations:
127-
128-
```bash
129-
pnpm db:migrate
130-
```
131-
132-
- Open Drizzle Studio to manage database:
133-
```bash
134-
pnpm db:studio
135-
```
136-
137-
## Project Structure
138-
139-
- `/src`: Source code
140-
- `/lib`: Library code
141-
- `/server`: Server-side code
142-
- `/db`: Database models and operations
143-
- `/routes`: SvelteKit routes
144-
- `/static`: Static assets
145-
146-
## Configuration
147-
148-
The application requires several environment variables to be set in the `.env` file:
149-
150-
### Database Configuration
111+
Create an `.env.development` file:
151112

152-
```
153-
DATABASE_URL=postgresql://root:mysecretpassword@localhost:5432/snapsort
154-
POSTGRES_USER=root
155-
POSTGRES_PASSWORD=mysecretpassword
156-
```
157-
158-
### External Tools
113+
```dotenv
114+
# Database credentials
115+
DATABASE_URL="file:/path/to/db.sqlite3"
159116
160-
```
117+
# Path to external binaries
161118
EXIFTOOL_PATH="/path/to/exiftool"
162-
FFMPEG_PATH="/path/to/ffmpeg"
163-
```
164-
165-
### File Storage
119+
FFMPEG_PATH="/path/toffmpeg"
166120
167-
```
121+
# Path to data storage
168122
FILE_UPLOAD_DIR="/path/to/uploaded-files"
169123
LIBRARY_ROOT_DIR="/path/to/library"
170124
```
171125

172-
## Usage
126+
Run database migrations and fire up the server:
127+
128+
```bash
129+
pnpm db:migrate:dev
130+
pnpm dev
131+
```
173132

174-
1. Start the application and navigate to the web interface
175-
2. Create new keywords
176-
3. Upload your media files
177-
4. Edit metadata as needed (date/time, description, GPS data, keywords)
178-
5. Apply the changes to temporarily modify the queued files
179-
6. Move files to the library to permanently save files
180-
7. Export metadata when needed for backup
133+
If you want to run a production server, you need to create an `.env.production` file and run `pnpm start`.
134+
135+
### Project structure
136+
137+
- `src/`:
138+
- `lib/`:
139+
- `components/`: Contains various UI components which can be imported in Svelte Pages
140+
- `server/`: Server-only code
141+
- `db/`:
142+
- `index.ts`: Manages database connection and exposes a wrapper for all database interactions
143+
- `schema.ts`: Defines the database structure which Drizzle uses to create migrations
144+
- `exiftool-wrapper.ts`: Manages all interactions with ExifTool
145+
- `file-manager.ts`: Handles all operations for uploaded files (create, rename, copy, delete)
146+
- `validation-schema.ts`: Zod schemas to validate external input
147+
- `routes/`: SvelteKit routes
148+
- `api/`
149+
- `export-exif/+server.ts`: Endpoint for exporting Exif data for all library files
150+
- `thumbnail/[file_id]/+server.ts`: Endpoint for fetching thumbnail using the file ID
151+
152+
## Future Improvements
153+
154+
- Google Photos Integration: Currently, I use Google Photos as a cloud backup (I know it's not a real backup, hush!).
155+
Once the files are committed to the library, they should also be uploaded to Google Photos. In the distant future, I
156+
might look into extending this to multiple cloud providers.
157+
- Add Tests: Now that the MVP is developed, a robust testing suite is needed. My photos are too precious to expose to
158+
untested code.
159+
- Backup/Restore: It's "technically" possible by manually cloning the app-data folder... But perhaps something more
160+
robust.
161+
- Multi-user Support: The more, the merrier!
162+
- Modify/Delete Existing Keywords: So far, I haven't faced a need to update a Keyword once it's created. Nonetheless, it
163+
is a useful feature.
164+
- Custom File Formats: I know I said it's opinionated, but it would still be nice to let users decide how they want
165+
their media to be organized.

0 commit comments

Comments
 (0)