ChronoFrame Documentation

repository·main·Indexed 23 days ago

https://github.com/hoshinosuzumi/chronoframe

A self-hosted personal photo gallery application for photographers featuring smooth rendering, EXIF metadata extraction, and map-based exploration. Supports multiple storage backends including local filesystem, S3-compatible storage (AWS, Cloudflare R2, MinIO), and OpenList, as well as map providers like MapLibre and Mapbox.

Tokens
24.4K
Snippets
55
Records
95
Agent score
80%

What's inside ChronoFrame

  1. Overview of ChronoFrame features

    main

    ChronoFrame is a self-hosted personal photo gallery designed for managing and browsing photos online. Key capabilities include:

    • Powerful Photo Management: Web interface for browsing and viewing photo locations on a map.
    • Simple Deployment: One-command deployment via Docker using SQLite3 (no external database required).
    • Flexible Storage: Supports multiple backends including local filesystems and S3-compatible storage.
    • Smart Geolocation: Automatic extraction of GPS metadata with support for Mapbox geocoding and map displays.
    • Responsive Design: Optimized for desktop and mobile with touch and gesture support.
    • Live/Motion Photo Support: Native support for Apple LivePhoto and Google Motion Photo formats, including automatic processing of MOV video files to preserve dynamic effects.
  2. How location providers work in ChronoFrame

    main

    Location providers handle Reverse Geocoding, which is the process of converting photo GPS coordinates (latitude and longitude) into human-readable city or country names during photo processing.

    By default, ChronoFrame uses OpenStreetMap Nominatim and requires no configuration. You should only configure a custom provider if your server is in mainland China or if the connection to Nominatim is blocked.

  3. Implement conditional field visibility

    main

    You can show or hide a setting based on the value of another field by using the visibleIf property in the UI configuration (ui-config.ts).

    visibleIf requires an object with:

    • fieldKey: The key of the field to watch.
    • value: The value that triggers visibility.
    foo: {
      type: 'input',
      placeholder: 'Only show when bar = "baz"',
      visibleIf: { fieldKey: 'bar', value: 'baz' },
    }
  4. Configure UI for a new setting

    main

    After defining the field, you must specify how it renders in the UI by editing server/services/settings/ui-config.ts. You add a configuration object to the corresponding UI constant (e.g., APP_SETTINGS_UI).

    Available type options: input, password, url, textarea, select, radio, tabs, toggle, number.

    Available configuration keys:

    • type: The UI component type.
    • placeholder: Placeholder text for inputs.
    • help: A translation key for help text (optional).
    • required: Boolean indicating if the field is mandatory (optional).
    • visibleIf: An object used for conditional visibility (see Conditional Fields).
  5. Deploy ChronoFrame with Docker

    main

    The recommended way to deploy ChronoFrame is using the prebuilt Docker image. You must create a .env file to configure required environment variables before running the container.

    Quick Start with Docker CLI

    Run the following command to start the container with a local data volume:

    docker run -d --name chronoframe -p 3000:3000 -v $(pwd)/data:/app/data --env-file .env ghcr.io/hoshinosuzumi/chronoframe:latest

    Deployment with Docker Compose

    Create a docker-compose.yml file:

    services:
      chronoframe:
        image: ghcr.io/hoshinosuzumi/chronoframe:latest
        container_name: chronoframe
        restart: unless-stopped
        ports:
          - '3000:3000'
        volumes:
          - ./data:/app/data
        env_file:
          - .env

    Then start the service with:

    docker compose up -d
  6. Deploy ChronoFrame using Docker Compose

    main

    Create a docker-compose.yml file to manage the ChronoFrame lifecycle.

    services:
      chronoframe:
        image: ghcr.io/hoshinosuzumi/chronoframe:latest
        container_name: chronoframe
        restart: unless-stopped
        ports:
          - '3000:3000'
        volumes:
          - ./data:/app/data
        env_file:
          - .env

    Lifecycle Commands

    # Start the service
    docker compose up -d
    
    # Follow logs
    docker compose logs -f chronoframe
    
    # Stop the service
    docker compose down
    
    # Update to the latest image
    docker compose pull
    docker compose up -d
  7. How to use ChronoFrame

    main

    Logging In

    1. Click the avatar to go to the login page.
    2. Use your credentials or log in via GitHub. Note: If you haven't configured CFRAME_ADMIN_EMAIL and CFRAME_ADMIN_PASSWORD, the default credentials are:
    • Email: admin@chronoframe.com
    • Password: CF1234@!

    Uploading Photos

    1. Navigate to the dashboard at /dashboard.
    2. Go to the Photos page.
    3. Select images or drag and drop them to upload. The system automatically extracts EXIF data, generates thumbnails, and performs reverse geocoding for location data.

    Live Photos (MOV + HEIC)

    ChronoFrame supports Live Photos by matching .heic and .mov files with identical filenames (e.g., IMG_1234.heic and IMG_1234.mov). If they are not automatically paired, you can manually trigger pairing detection in the dashboard image menu.

  8. Update ChronoFrame using a single container

    main

    If you are not using Docker Compose, you can update the single container manually:

    # Stop existing container
    docker stop chronoframe
    docker rm chronoframe
    
    # Pull latest image
    docker pull ghcr.io/hoshinosuzumi/chronoframe:latest
    
    # Start new container with same configuration
    docker run -d \
      --name chronoframe \
      -p 3000:3000 \
      -v $(pwd)/data:/app/data \
      --env-file .env \
      ghcr.io/hoshinosuzumi/chronoframe:latest
  9. Configure MinIO with Path-Style Access

    main

    When using a self-hosted MinIO instance, you must enable path-style access by setting NUXT_PROVIDER_S3_FORCE_PATH_STYLE=true.

    NUXT_STORAGE_PROVIDER=s3
    NUXT_PROVIDER_S3_ENDPOINT=https://minio.example.com
    NUXT_PROVIDER_S3_BUCKET=chronoframe
    NUXT_PROVIDER_S3_REGION=us-east-1
    NUXT_PROVIDER_S3_ACCESS_KEY_ID=minioadmin
    NUXT_PROVIDER_S3_SECRET_ACCESS_KEY=minioadmin
    # MinIO requires path-style access
    NUXT_PROVIDER_S3_FORCE_PATH_STYLE=true