A very opinionated solution for a very personal problem of organizing a photos/videos library. SnapSort helps you (read: me) organize media files (images/videos) and edit metadata.
- Create Keywords: Create different types of keywords (Album, Location, Person, Animal, Group, or Other) which can be used to tag files.
- Edit Metadata: Modify capture date and time, title/descriptions, GPS data, and keywords for your media files.
- Batch Editing: Apply metadata changes to multiple files at once, saving time and ensuring consistency.
- View Metadata: View all metadata associated with your library files.
- EXIF Data Export: Export metadata from your library files for backup or analysis.
Media library is organized in a "Year / Month / Day" hierarchy. The Day folder may have a - Keyword
suffix
depending on whether any of the files within that folder contains a keyword which can be used as a folder label.
The files use the following naming convention: TAG-YYYYMMDD-INDEX
TAG
will be IMG
or VID
depending on the type of the media. A special keyword Edit
can be added to the file to
overwrite TAG
to be EDT
.
library/
|- 2025/
|- 01 - January/
|- 01/
|- IMG-20250101-000.jpg
|- VID-20250101-000.mp4
|- 02 - Birthday/
|- EDT-20250102-000.jpg
|- IMG-20250102-000.jpg
|- IMG-20250102-001.jpg
Prerequisites:
Docker Compose configuration:
services:
snapsort:
image: bhatushar/snapsort
ports:
- '3990:3990'
volumes:
- '/app-data:/app/data'
- '/library:/app/library'
environment:
TZ: Asia/Calcutta
restart: unless-stopped
/app-data
is where SnapSort will store its internal files like the database, user-uploaded media, and thumbnails.
/library
is where your media will go once processed by SnapSort.
Run the container with docker compose up -d
and you should be able to access the website on localhost:3990
.
When you first launch the application, it will ask you to create a login password. SnapSort currently doesn't support
multiple users.
After logging in, you'll land on the homepage where you can upload new media files for processing. You can edit the date
and time information, add titles to your media, tag them with keywords... Oh wait, you can't use keywords?
That's because you need to create the keywords first!
Go to Settings > Manage Keywords. On the top-right, there will be an option to add keywords.
Here, you can set the name of the keyword, its type/category, and whether to use it to label folders.
Now you can go back and start tagging your files.
Whatever changes you make will not persist until you save them. When you click the 'Save' button, you get two options:
- Apply Changes: This will only store your changes in SnapSort's internal database. Your files will remain intact. This is useful if you want to come back in the future and revise your changes.
- Move to Library: This is the final step. It will apply your changes to your files and move them to the library.
This project is developed using the SvelteKit framework with TypeScript support. It uses a locally hosted SQLite
database, and the DB connection is managed by Drizzle.
Internally, it relies on ExifTool (for reading/writing metadata) and
FFmpeg (for generating thumbnails for videos).
Set up the project:
git clone https://github.com/bhatushar/snapsort.git
cd snapsort
pnpm install
Create an .env.development
file:
# Database credentials
DATABASE_URL="file:/path/to/db.sqlite3"
# Path to external binaries
EXIFTOOL_PATH="/path/to/exiftool"
FFMPEG_PATH="/path/toffmpeg"
# Path to data storage
FILE_UPLOAD_DIR="/path/to/uploaded-files"
LIBRARY_ROOT_DIR="/path/to/library"
Run database migrations and fire up the server:
pnpm db:migrate:dev
pnpm dev
If you want to run a production server, you need to create an .env.production
file and run pnpm start
.
src/
:lib/
:components/
: Contains various UI components which can be imported in Svelte Pagesserver/
: Server-only codedb/
:index.ts
: Manages database connection and exposes a wrapper for all database interactionsschema.ts
: Defines the database structure which Drizzle uses to create migrations
exiftool-wrapper.ts
: Manages all interactions with ExifToolfile-manager.ts
: Handles all operations for uploaded files (create, rename, copy, delete)validation-schema.ts
: Zod schemas to validate external input
routes/
: SvelteKit routesapi/
export-exif/+server.ts
: Endpoint for exporting Exif data for all library filesthumbnail/[file_id]/+server.ts
: Endpoint for fetching thumbnail using the file ID
- Google Photos Integration: Currently, I use Google Photos as a cloud backup (I know it's not a real backup, hush!). Once the files are committed to the library, they should also be uploaded to Google Photos. In the distant future, I might look into extending this to multiple cloud providers.
- Add Tests: Now that the MVP is developed, a robust testing suite is needed. My photos are too precious to expose to untested code.
- Backup/Restore: It's "technically" possible by manually cloning the app-data folder... But perhaps something more robust.
- Multi-user Support: The more, the merrier!
- Modify/Delete Existing Keywords: So far, I haven't faced a need to update a Keyword once it's created. Nonetheless, it is a useful feature.
- Custom File Formats: I know I said it's opinionated, but it would still be nice to let users decide how they want their media to be organized.