176 lines
7.2 KiB
Markdown
176 lines
7.2 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
Additional guidance is provided in @AGENTS.md
|
||
|
||
## Project Overview
|
||
|
||
Nibasa Viewer is a lightweight, pure HTML+CSS gallery viewer designed for compatibility with older browsers. It uses Django as a backend framework but serves images directly from the filesystem rather than using database models.
|
||
|
||
**Key Design Principles:**
|
||
- Filesystem-first architecture (no image/folder models in database)
|
||
- No JavaScript or modern frontend frameworks
|
||
- Broad browser compatibility (uses HTML tables, not flexbox/grid)
|
||
- Dark theme optimized for image viewing
|
||
- Lazy thumbnail generation with on-disk caching
|
||
|
||
## Development Commands
|
||
|
||
```bash
|
||
# Install dependencies
|
||
pip install -r requirements.txt
|
||
|
||
# Run development server
|
||
python manage.py runserver
|
||
|
||
# Create user for gallery access (required)
|
||
python manage.py shell
|
||
>>> from django.contrib.auth.models import User
|
||
>>> user = User.objects.create_user('<USERNAME>', '<EMAIL>', '<PASSWORD>')
|
||
>>> user.save()
|
||
>>> exit()
|
||
|
||
# Pre-generate all thumbnails (optional, done on-demand otherwise)
|
||
python manage.py makethumbnails
|
||
|
||
# Django admin commands
|
||
python manage.py migrate
|
||
python manage.py createsuperuser
|
||
python manage.py collectstatic
|
||
```
|
||
|
||
## Architecture
|
||
|
||
### Single App Structure
|
||
|
||
The project has one Django app: **`viewer`**. All gallery functionality is consolidated here:
|
||
- `views.py` - Gallery directory browsing and image viewing (viewer/views.py:65-189)
|
||
- `utils.py` - Thumbnail generation helpers
|
||
- `templates/` - Pure HTML templates (no JavaScript)
|
||
- `static/` - CSS styling and navigation icons
|
||
- `views.py` - Thin delegating entry points that route to `viewer/directory.py` and `viewer/image.py` (see `gallery_view` in `viewer/views.py`).
|
||
- `directory.py` - Directory browsing, search, and list rendering helpers.
|
||
- `image.py` - Single-image rendering and metadata helpers.
|
||
- `common.py` - Shared helpers: URL/query builders, sorting, breadcrumbs, thumbnail utilities.
|
||
- `utils.py` - Thumbnail generation helpers.
|
||
- `templates/` - HTML templates (minimal JS via Bootstrap where needed).
|
||
- `static/` - CSS styling and navigation icons
|
||
|
||
### Gallery Data Flow
|
||
|
||
**Filesystem as Data Source:**
|
||
- Images served from `GALLERY_ROOT` path (configured in `.env`)
|
||
- Thumbnails cached in `THUMBNAILS_ROOT` path
|
||
- No database models for images or directories
|
||
- Directory structure navigated using Python's `pathlib`
|
||
|
||
**Static File Routing:**
|
||
- `/imgs/` → Original images from `GALLERY_ROOT`
|
||
- `/thumbs/` → Cached thumbnails from `THUMBNAILS_ROOT`
|
||
- `/static/` → CSS and navigation icons
|
||
|
||
### Authentication
|
||
|
||
Uses Django's built-in `django.contrib.auth` system:
|
||
- All gallery views protected with `@login_required` decorator
|
||
- Users manually created via Django shell (no signup form)
|
||
- Database only stores user accounts (SQLite)
|
||
- Login/logout redirects configured in NibasaViewer/settings.py:108-110
|
||
|
||
### View Logic
|
||
|
||
**`gallery_view()` function** (viewer/views.py:65-189) handles both:
|
||
|
||
1. **Directory browsing** when path points to folder:
|
||
- Lists subdirectories and images
|
||
- Supports search with recursive directory scanning (`viewer/directory.py:do_recursive_search`)
|
||
- Does not use server-side pagination; the gallery returns full image lists and templates render them in a grid
|
||
- Converts image lists to structured context used by templates
|
||
|
||
2. **Image viewing** when path points to file:
|
||
- Displays single image with prev/next navigation
|
||
- Finds sibling images in same directory
|
||
- Links to full-resolution image
|
||
|
||
The image view logic now lives in `viewer/image.py` and exposes additional context keys used by templates and tests (see `viewer/test.py`): `prev_url`, `next_url`, `prev_thumb`, `next_thumb`, `back_url`, `back_thumb`, `home_url`, `home_thumb`, and `image_meta` (filename/width/height/filesize/created/modified).
|
||
|
||
### Thumbnail Generation
|
||
|
||
**Lazy generation approach** (viewer/utils.py):
|
||
- Thumbnails created on-demand when viewing gallery
|
||
- 128×128 pixel size (`THUMB_SIZE`) and cached under `THUMBNAILS_ROOT`
|
||
- Uses Pillow for image processing
|
||
- Fast extension-based image detection (no MIME-type I/O)
|
||
|
||
**Batch pre-generation:**
|
||
- `python manage.py makethumbnails` command available
|
||
- Useful for initial setup or after adding many images
|
||
|
||
### Performance Optimizations
|
||
|
||
**Extension-based image filtering** (viewer/utils.py:17-27):
|
||
- Uses `is_image_file()` helper that checks file extensions instead of reading file contents
|
||
- Supported extensions defined in `IMAGE_EXTENSIONS` constant
|
||
- Eliminates ~99% of I/O operations when listing directories
|
||
- Significantly faster than MIME-type detection for large directories
|
||
|
||
## Configuration
|
||
|
||
### Required Environment Variables
|
||
|
||
Create `.env` (not in git):
|
||
|
||
```env
|
||
GALLERY_ROOT=/path/to/your/images
|
||
THUMBNAILS_ROOT=/path/to/thumbnail/cache
|
||
```
|
||
|
||
`settings.py` loads `.env` with `python-dotenv` and parses both values as `pathlib.Path`. Each variable is optional and resolves to `None` when unset or empty.
|
||
|
||
### Pagination Constants
|
||
|
||
Defined in viewer/views.py:23-25:
|
||
- `CELLS_PER_ROW = 7` - Image grid columns
|
||
- `ROWS_PER_PAGE = 4` - Image grid rows
|
||
- `IMAGES_PER_PAGE = 28` - Total images per page
|
||
|
||
## Production Deployment
|
||
|
||
Systemd service files included for Gunicorn deployment:
|
||
- `nibasaviewer.service` - Service configuration
|
||
- `nibasaviewer.socket` - Socket activation
|
||
|
||
Default production location: `/var/lib/NibasaViewer`
|
||
|
||
## Dependencies
|
||
|
||
- **Django 4.2.3** - Web framework
|
||
- **Pillow 10.0.0** - Image processing (thumbnails)
|
||
- **python-dotenv 1.1.1** - Loads local `.env` configuration
|
||
- **gunicorn 21.2.0** - WSGI server (production)
|
||
|
||
## Code Patterns
|
||
|
||
**Template rendering:**
|
||
- All views use `render(request, template, context)`
|
||
- Context includes pagination data, image paths, and navigation state
|
||
|
||
**Path handling:**
|
||
- Use `pathlib.Path` for all filesystem operations
|
||
- Convert to relative paths for URLs: `image.relative_to(settings.GALLERY_ROOT)`
|
||
- Gallery URLs follow pattern: `/gallery/{relative_path}`
|
||
|
||
**Image filtering:**
|
||
- Use `is_image_file(path)` from `viewer.utils` to validate image files
|
||
- Fast extension-based detection (checks `IMAGE_EXTENSIONS` set)
|
||
- Supports common formats: JPEG, PNG, GIF, WebP, BMP, TIFF, SVG
|
||
- Accepts both `pathlib.Path` and string paths
|
||
|
||
### Recent changes notes
|
||
|
||
- The image view was refactored to match the gallery layout and styling; `viewer/templates/image_view.html` now uses the shared `viewer/static/css/styles.css` file and Bootstrap/Font Awesome includes like `gallery_view.html`.
|
||
- `_render_image` in `viewer/views.py` now exposes additional context keys used by the template and tests: `prev_url`, `next_url`, `prev_thumb`, `next_thumb`, `back_url`, `back_thumb`, `home_url`, `home_thumb`, and `image_meta` (dictionary with `filename`, `width`, `height`, `filesize`, `created`, `modified`). Agents modifying image-view behavior should update tests in `viewer/test.py` as well.
|
||
- The top-bar sort button for the image view was replaced by an Info button (`fa-circle-info`) which shows a dropdown containing image metadata. The dropdown is vertically scrollable for long content.
|
||
- The main displayed image now uses the same drop shadow and rounded corners as thumbnails (styles added to `viewer/static/css/styles.css`).
|