Files
NibasaViewer/CLAUDE.md

6.2 KiB
Raw Blame History

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

# 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

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/views.py:32-52)
    • Paginates images at 28 per page (7 columns × 4 rows)
    • Converts flat image lists to table rows for HTML rendering
  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

Thumbnail Generation

Lazy generation approach (viewer/utils.py):

  • Thumbnails created on-demand when viewing gallery
  • 128×128 pixel size (hardcoded)
  • 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):

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).