Feature: Photo Library & Scanning
Relevant source files
The following files were used as context for generating this wiki page:
The Photo Library and Scanning feature is the core system for populating the Pixona application with user media. It is responsible for discovering, indexing, and persisting metadata for photos and videos from the local file system. This process involves a coordinated effort between the React-based user interface (Renderer Process) and the Node.js-based backend (Main Process) within the Electron framework.
The system is designed to scan specified directories, filter for supported media types, extract file metadata, and store this information in a local IndexedDB database. The user initiates this process through the UI, which then displays the indexed media in a grid-based library view.
Architecture Overview
The feature's architecture leverages Electron's multi-process model. The Renderer Process (React UI) cannot directly access the file system for security reasons. Instead, it communicates with the Main Process via an IPC (Inter-Process Communication) bridge defined in the preload script. The Main Process has full Node.js API access to perform file system operations like scanning directories and reading file metadata.
Sources: electron/main.ts, electron/preload.ts, src/components/ImportDialog.tsx
This diagram shows the high-level interaction between the Renderer and Main processes for file scanning.
Photo Import and Scanning Flow
The import process is user-initiated and follows a clear sequence of events, moving from the UI layer to the backend for processing, and finally persisting the data for display.
Sources: src/components/Sidebar.tsx, src/components/ImportDialog.tsx, electron/preload.ts, electron/main.ts, src/lib/db.ts
1. User Initiation
The flow begins when the user clicks the "Import Photos" button located in the main Sidebar component. This action opens the ImportDialog modal, presenting the user with options to import from a folder or a drive.
Sources: src/components/Sidebar.tsx:28-32, src/components/ImportDialog.tsx
2. Directory Selection and Scan Invocation
When the user selects "From Folder", the handleImportFromFolder function in ImportDialog.tsx is triggered. This function uses the window.electron.selectFolder() API exposed by the preload script to open a native OS folder selection dialog.
If the user selects one or more folders, the component then:
- Sets up a listener
window.electron.onScanProgress()to receive real-time updates on the scanning process. - Iterates through the selected folders and calls
window.electron.scanDirectory(folder)for each one. This is an asynchronous IPC call to the main process to start the file system scan.
Sources: src/components/ImportDialog.tsx:22-48, electron/preload.ts:8-11
3. Data Processing and Storage
After the scanDirectory calls complete, the collected file information is processed in the ImportDialog:
- The raw file list from the main process is mapped into an array of
PhotoMetadataobjects. - These objects are added to the IndexedDB
photosstore in batches of 100 to avoid overwhelming the database with a single large transaction. - The UI progress bar is updated as batches are inserted.
- Upon completion, a success toast is shown, and the page is reloaded to reflect the newly imported photos.
Sources: src/components/ImportDialog.tsx:55-76, src/lib/db.ts:145-157
Sequence Diagram of Import Flow
The following diagram illustrates the sequence of interactions between the user, the renderer process, and the main process during a folder import.
Backend File Scanning
The core file system scanning logic resides in electron/main.ts. It is exposed to the renderer process via a set of secure IPC handlers.
Sources: electron/main.ts:110-185
IPC Handlers
The main process listens for specific events from the renderer. The primary handlers for this feature are:
| Handler Name | Description | File |
|---|---|---|
get-drives | Detects and returns a list of available disk drives on Windows (e.g., C:/, D:/). | electron/main.ts:91 |
select-folder | Opens a native dialog for the user to select one or more directories. | electron/main.ts:110 |
scan-directory | Recursively scans a given directory path for supported media files and returns their metadata. | electron/main.ts:128 |
scan-progress | A channel (not a handler) used to send real-time scanning progress from the main process to the renderer. | electron/main.ts:160 |
Scanning Logic (scan-directory)
The scan-directory handler implements a recursive function scanDir to traverse the file system.
- File Type Filtering: It only indexes files with specific extensions.
- Directory Exclusion: It explicitly skips system, hidden, and development-related folders to improve performance and avoid irrelevant files.
- Metadata Extraction: For each valid file, it uses
fs.statto retrieve size, creation time, and modification time. - Progress Reporting: Periodically, it sends a
scan-progressevent back to the renderer containing the current path being scanned and the number of files found so far.
The following flowchart details the logic within the scanDir function.
Sources: electron/main.ts:131-185
Supported File Formats
The scanner is configured to look for a specific set of image and video file extensions.
| Type | Extensions |
|---|---|
| Images | .jpg, .jpeg, .png, .gif, .bmp, .webp, .heic, .heif, .tiff, .raw, .cr2, .nef, .arw |
| Videos | .mp4, .mov, .avi, .mkv, .webm, .m4v, .wmv, .flv, .3gp |
Sources: electron/main.ts:132-134
Data Storage and Model
Scanned photo information is persisted in the browser's IndexedDB to ensure fast access without re-scanning the file system on every app launch.
Sources: src/lib/db.ts
Database Schema
A PhotoDatabase class encapsulates all IndexedDB operations. It defines a database named pixona_photos_db with several object stores. The primary store for this feature is photos.
This ER diagram shows the structure of the photos object store in IndexedDB.
Sources: src/lib/db.ts:8-39, 70-80
The PhotoMetadata Data Model
All information about a photo is stored in an object that conforms to the PhotoMetadata interface.
// Source: src/lib/db.ts:13-39
export interface PhotoMetadata {
id: string;
path: string;
name: string;
type: 'image' | 'video';
size: number;
created: Date;
modified: Date;
imported: Date;
width?: number;
height?: number;
duration?: number; // for videos
location?: {
lat: number;
lng: number;
name?: string;
};
tags: string[];
albumIds: string[];
peopleIds: string[];
hash?: string; // for duplicate detection
thumbnailData?: string; // base64 thumbnail
metadata?: {
camera?: string;
lens?: string;
focalLength?: string;
aperture?: string;
iso?: string;
shutterSpeed?: string;
};
}
Library Display
Once photos are imported and stored in the database, they are displayed in the main Library view.
Library.tsx Page
This component serves as the main view for all photos. It orchestrates the display and manages UI state related to the library, such as selection mode for batch editing. It fetches the photo data (currently using mock data, but intended to use db.getAllPhotos()) and passes it down to the PhotoGrid component for rendering.
Sources: src/pages/Library.tsx:44-50
PhotoGrid.tsx Component
The PhotoGrid component is responsible for rendering the visual grid of photos. It receives an array of photo objects and maps them to individual grid items. While the source code for this component was not provided for analysis, its usage in Library.tsx indicates it handles the layout and click events for each photo in the grid.
Sources: src/pages/Library.tsx:44-50
Conclusion
The Photo Library & Scanning feature is a well-structured system that securely and efficiently bridges the gap between the user's file system and the web-based technologies of the application's UI. By delegating file system access to the Electron main process and using an asynchronous, event-driven model for communication, it provides a responsive user experience with real-time progress feedback. The use of IndexedDB for data persistence ensures that the library is durable and performs well after the initial import.