# J621 Self-hosted media library and e621 archive manager, rebuilt as a **React SPA + Django REST API**. ## Structure ``` backend/ Django 6 + DRF API (MariaDB + Redis via docker compose) frontend/ Vite + React + TypeScript SPA ``` ## Development ### Backend ```bash cd backend source venv/bin/activate python manage.py migrate python manage.py scan_files # index the watched folder python manage.py runserver ``` Copy `.env.example` to `.env` and set `WATCHED_FOLDER` before scanning. ### Frontend ```bash cd frontend npm install npm run dev # http://localhost:5173, proxies /api to :8000 ``` ### Production Docker: see [`deploy/`](deploy/README.md) for the two images (SPA on static nginx, API on gunicorn), the three compose variants (both / frontend-only / backend-only) behind a shared nginx service and a Tailscale sidecar, and the public-funnel or tailnet-only serve configs. `deploy/push_*.sh` builds and pushes the multi-arch images to the Gitea registry. ## Random image endpoint Used by the SPA's Random page and by shell greetings (fish_greeting + fastfetch): ```bash curl -H "Authorization: Token " \ "https://j621.example.ts.net/api/random/?rating=s,q&fastfetch=1" ``` ```json { "j_id": "J-59", "filename": "J-59.jpg", "extension": "jpg", "rating": "e", "url": "https://j621.example.ts.net/api/files/J-59/raw/?sig=…", "download_url": "https://j621.example.ts.net/api/files/J-59/raw/?sig=…&download=1", "thumbnail_url": "https://j621.example.ts.net/api/files/J-59/thumbnail/?sig=…", "fastfetch": true } ``` - `rating` — comma separated subset of `s`, `q`, `e` (default: any). - `fastfetch=1`, or any request whose User-Agent contains `fastfetch`, limits the roll to `png`/`jpg`/`gif` so terminals can display it. Images are the only candidates in both modes. - `url` is absolute, and signed for authenticated callers, so fastfetch can load it without headers. Guests get an unsigned URL and only see guest-visible items. - `/random` and `/random/` are aliases of `/api/random/` for scripts. Behind the bundled nginx those aliases negotiate on `Accept`: browsers get the SPA page, requesters like curl/wget/fastfetch get the JSON. `/api/random/` is the unambiguous path for scripts; 404 when nothing matches the filters. ## Licence Source-available, **non-commercial**: personal and other non-commercial use is welcome under the [Jake Labs Non-Commercial Software Licence](LICENSE), which requires attribution and keeps derivative works under the same licence. Commercial use is not permitted. Third-party dependencies keep their own licences (all permissive: MIT, BSD, Apache-2.0, ISC).