thumbsup

repository·master·Indexed 19 days ago

https://github.com/thumbsup/thumbsup

A command-line static gallery generator that converts folders of photos and videos into mobile-friendly, customizable web galleries. Version 2.18.0 supports various themes, JSON configuration, and Docker deployment. It requires Node.js, exiftool, and GraphicsMagick, with optional support for FFmpeg, Gifsicle, dcraw, and ImageMagick for specific formats.

Tokens
8.5K
Snippets
22
Records
34
Agent score
73%

What's inside thumbsup

  1. Define jobs for ListrWorkQueue

    master

    Jobs in a ListrWorkQueue are objects that follow a structure similar to standard Listr tasks. Each job must contain a title and a task property. The task property must be a function that returns a Promise. Note that Observables and streams are not supported.

    {
      title: 'Job A',
      task: () => new Promise(resolve => setTimeout(resolve, 1000))
    }
  2. Understand the exiftool-batch stream entry format

    master

    Each object emitted by the stream follows a structure identical to the raw JSON output from exiftool.

    Key characteristics:

    • SourceFile: A relative path to the root folder provided to parse().
    • Tag Groups: Data is organized into groups like File, EXIF, and Composite.
    • Fidelity: The module does not attempt to parse date strings, assume timezones, fix GPS format oddities (e.g., mixing numbers and strings), or merge similar fields (like EXIF:ImageDescription and IPTC:Caption-Abstract).
    • Naming: Group and tag names match the official exiftool documentation.
    {
      SourceFile: 'NewYork/IMG_5364.jpg',
      File: {
        FileSize: '449 kB',
        MIMEType: 'image/jpeg',
        /* ... */
      },
      EXIF: {
        Orientation: 'Horizontal (normal)',
        DateTimeOriginal: '2017:01:07 13:59:56',
        /* ... */
      },
      Composite: {
        GPSLatitude: '+51.5285578',
        GPSLongitude: -0.2420248,
        /* ... */
      }
    }
  3. Understand the metadata format

    master

    The metadata object emitted for each file contains all metadata embedded inside the image or video files in the raw exiftool format. This includes standard file information, EXIF data, and composite data (like GPS coordinates).

    {
      "SourceFile": "NewYork/IMG_5364.jpg",
      "File": {
        "FileSize": "449 kB",
        "MIMEType": "image/jpeg"
      },
      "EXIF": {
        "Orientation": "Horizontal (normal)",
        "DateTimeOriginal": "2017:01:07 13:59:56"
      },
      "Composite": {
        "GPSLatitude": "+51.5285578",
        "GPSLongitude": -0.2420248
      }
    }
  4. Quick start with thumbsup

    master

    To turn a folder of photos and videos into a web gallery, install thumbsup globally via npm and point it to your input and output directories. Nested folders in your input directory will automatically become separate albums in the generated gallery.

    npm install -g thumbsup
    thumbsup --input ./photos --output ./gallery
  5. Use ListrWorkQueue for concurrent task processing

    master

    If you are using Listr and need to process a large number of tasks concurrently without cluttering the terminal, use ListrWorkQueue. Unlike the standard concurrent: <count> option in Listr, ListrWorkQueue only renders tasks as they are picked up from the queue and removes them once they are processed. This keeps the terminal output clean by focusing only on active tasks.

    const Listr = require('listr')
    const ListrWorkQueue = require('./listr-work-queue/index.js')
    
    const tasks = new Listr([{
      title: 'Running jobs',
      task: () => new ListrWorkQueue(/* tasks */, {
        concurrent: WORKER_COUNT,
        exitOnError: false
      })
    }])
    
    tasks.run().then(() => console.log('Done'))
  6. Use a JSON configuration file

    master

    Instead of passing many command line arguments, you can use a JSON configuration file. The file should contain a single object where each key corresponds to a command line argument (without the leading --).

    Example config.json:

    {
      "sort-albums-by": "start-date"
    }

    Then run thumbsup with the --config flag:

    thumbsup --config config.json
  7. Use exiftool-batch to process files in parallel

    master

    The exiftool-batch module allows you to process a batch of files through exiftool and receive the results via a Node.js stream. It uses exiftool in batch mode and runs one process per CPU core by default to maximize performance.

    To use it, call exiftool.parse(root, files, [count]) where:

    • root: The base directory for the files.
    • files: An array of filenames to process.
    • count (optional): The number of parallel exiftool processes to run. If omitted, it defaults to the CPU count.
    const exiftool = require('./exiftool-batch/parallel')
    const stream = exiftool.parse('./photos', [
      'IMG_000001.jpg',
      'IMG_000002.jpg',
      'IMG_000003.jpg'
    ])
    
    stream.on('data', entry => console.log(`Processed ${entry.SourceFile}`))
    stream.on('end', () => console.log('Finished'))
  8. Run thumbsup using Docker

    master

    You can run thumbsup as a Docker container to avoid manual dependency installation. The container ghcr.io/thumbsup/thumbsup comes pre-packaged with all required dependencies.

    To run it, mount your current working directory to /work inside the container:

    docker run -v `pwd`:/work ghcr.io/thumbsup/thumbsup [...]
  9. Index a folder of photos and videos

    master

    Use the Index class to scan a directory, compare it against a local SQLite database, and cache metadata for fast retrieval. You can trigger an update by calling .update(path, options). This method returns an emitter that provides lifecycle events for stats, progress, individual files, and completion.

    const Index = require('./index/index')
    
    // Initialize with a database file name
    const index = new Index('thumbsup.db')
    
    // Start indexing a folder
    const emitter = index.update('/Volumes/photos', {
      concurrency: 2,
      includePhotos: true,
      includeVideos: true,
      includeRawPhotos: false,
    })
    
    // Listen for lifecycle events
    emitter.on('stats', stats => {
      // stats contains: total, unchanged, added, modified, deleted
    })
    
    emitter.on('progress', progress => {
      // progress contains: path, completed, total
    })
    
    emitter.on('file', file => {
      // file contains: path, timestamp, metadata
    })
    
    emitter.on('done', () => {
      console.log('Finished indexing')
    })
  10. Configure album mapping via --albums-from patterns

    master

    The AlbumMapper determines which albums a file belongs to based on a set of patterns. These patterns can be provided via the --albums-from command-line argument.

    Supported pattern types:

    1. String patterns: Standard patterns (e.g., using %path) that are parsed by the internal albumPattern engine.
    2. Custom mapper files: A string starting with file:// followed by the absolute path to a JavaScript file. This allows you to provide a custom function to handle mapping logic.
    3. Functions: Direct JavaScript functions passed into the mapper.

    If no patterns are provided, the mapper defaults to using ['%path'].

    # Example of using a string pattern via CLI (conceptual)
    thumbsup --albums-from "%path/%year/%month"
    
    # Example of using a custom mapper file via CLI (conceptual)
    thumbsup --albums-from "file:///absolute/path/to/my-mapper.js"
  11. Import Picasa metadata via picasa.ini files

    master

    The Picasa input provider allows you to import metadata for your images by reading <picasa.ini> files located within your input folders.

    Metadata is organized into two main types:

    1. Album Metadata: Stored under the [Picasa] section in the picasa.ini file.
    2. File Metadata: Stored under sections named after the specific file (e.g., [IMG_0001.jpg]).

    The provider automatically caches folder metadata in memory to optimize repeated lookups within the same directory.