PicList Advanced Synchronization Features: Multi-Cloud Config and Gallery Sync

PicList provides enterprise-grade synchronization capabilities supporting GitHub, Gitee, Gitea, and WebDAV backends, featuring conflict-aware gallery database merging, proxy support, and incremental configuration uploads through a unified TypeScript API.

The open-source image hosting tool PicList (kuingsmile/piclist) extends beyond simple uploads by offering robust advanced synchronization features that keep your configuration files and gallery databases consistent across multiple machines. Whether you need to sync settings between work and home computers or maintain a centralized gallery database in the cloud, PicList's synchronization subsystem handles complex conflict resolution and network configurations automatically.

Multi-Backend Cloud Synchronization Architecture

PicList's synchronization engine in src/main/utils/syncSettings.ts abstracts multiple storage providers behind a unified interface, allowing seamless switching between Git-based and WebDAV backends without changing the high-level API.

Supported Remote Storage Providers

The system currently supports four primary backend types, selected via the syncConfig.type property:

  • GitHub: Uses Octokit with optional HttpsProxyAgent for corporate environments
  • Gitee: Native API integration with Chinese hosting optimization
  • Gitea: Self-hosted Git platform support
  • WebDAV: Generic WebDAV endpoints with basic and digest authentication

Each backend implements the four core operations defined in syncSettings.ts: uploadLocalToRemote, updateLocalToRemote, downloadRemoteToLocal, and checkCloudFileExist.

Core Synchronization Logic in syncSettings.ts

The file src/main/utils/syncSettings.ts contains the primary orchestration logic. Key functions include:

  • getSyncConfig(): Retrieves user settings from picgo.getConfig<ISyncConfig>(configPaths.settings.sync) with sensible defaults
  • isSyncConfigValidate(): Validates required fields per backend type (e.g., username, repo, token for GitHub)
  • uploadFile(): Implements incremental logic—first attempting updateLocalToRemote, falling back to uploadLocalToRemote on 404 errors

Configuration File Synchronization

PicList treats configuration files (data.json, manage.json, etc.) as first-class synchronization citizens, exposing upload and download operations through RPC handlers in src/main/events/rpc/routes/setting/configure.ts.

Uploading Local Configurations

The RPC action CONFIGURE_UPLOAD_ALL_CONFIG triggers uploadFile() with an array of configuration filenames. This operation:

  1. Validates the sync configuration via isSyncConfigValidate()
  2. Iterates through the file list, calling uploadFunc for each
  3. Uses the incremental upload strategy (update first, then create)
import { uploadFile } from '~/utils/syncSettings';

const files = ['data.json', 'manage.json'];
const uploaded = await uploadFile(files);
console.log(`Uploaded ${uploaded} configuration files`);

Source: src/main/events/rpc/routes/setting/configure.ts lines 107-112

Downloading Remote Configurations

Conversely, CONFIGURE_DOWNLOAD_ALL_CONFIG invokes downloadFile(), which retrieves remote files via downloadRemoteToLocal() and writes them to the local data directory. This enables rapid restoration of settings on new machines.

import { downloadFile } from '~/utils/syncSettings';

await downloadFile(['data.json', 'manage.json']);

Source: src/main/events/rpc/routes/setting/configure.ts lines 128-133

Beyond static configuration files, PicList synchronizes the dynamic gallery database (gallery.db), implementing sophisticated merge logic to handle conflicts when the same image metadata exists in both local and remote versions.

Temporary Workspace Isolation

All gallery sync operations occur within an isolated temporary directory at $TMPDIR/piclist-sync-tmp. The system creates three distinct paths:

  • localDBPath: Copy of the current local database
  • remoteDBPath: Downloaded remote database
  • dbMerged: Output path for the merged result

This isolation ensures that failed syncs never corrupt the production database.

Timestamp-Based Merge Strategy

The mergeGalleryDB() function implements conflict resolution by comparing updatedAt timestamps:

  1. Builds a Map of all gallery items from both local and remote databases
  2. For items existing in both locations, selects the version with the newer updatedAt
  3. Respects settings.lastSyncTime to ignore stale remote items that haven't changed since the last synchronization
  4. Writes the merged result to dbMerged and uploads it back to the remote
import { syncGallery } from '~/utils/syncSettings';

const syncedCount = await syncGallery();
console.log(`Synchronized ${syncedCount} gallery databases`);

Source: src/main/utils/syncSettings.ts lines 82-88 and merge logic at lines 38-66

Enterprise Features: Proxy and Authentication

PicList's synchronization subsystem includes enterprise-grade networking features for restricted environments and secure authentication.

Corporate Proxy Support

The system automatically detects and uses proxy settings via HttpsProxyAgent for GitHub operations and Axios configurations for WebDAV. The proxy builder in src/main/utils/syncSettings.ts (lines 89-99) constructs the appropriate agent based on user settings, enabling synchronization behind corporate firewalls.

WebDAV Authentication Methods

For WebDAV backends, PicList supports both basic and digest authentication via the AuthType enum from the webdav package. The configuration interface ISyncConfig allows specifying webdavAuthType to match your server's security requirements.

Programmatic API Usage

While the PicList UI exposes these features through the settings panel, developers can invoke synchronization directly via the internal API.

Complete WebDAV Configuration Example

import { ISyncConfig } from '~/types/sync';
import { configPaths } from '~/utils/configPaths';

const webdavSync: ISyncConfig = {
  type: 'webdav',
  webdavEndpoint: 'https://webdav.example.com',
  webdavUsername: 'myUser',
  webdavPassword: 'myPass',
  webdavAuthType: 'digest',      // or 'basic'
  webdavSslEnabled: true,
  webdavSavePath: '/piclist-sync',
  proxy: '',                     // optional proxy URL
};

picgo.setConfig({ [configPaths.settings.sync]: webdavSync });

Source: Configuration schema defined in src/renderer/utils/configPaths.ts lines 57-58

Batch Configuration Synchronization

import { uploadFile, downloadFile } from '~/utils/syncSettings';

// Upload multiple config files
const uploadResult = await uploadFile(['data.json', 'manage.json', 'settings.json']);

// Download to restore on new machine
await downloadFile(['data.json', 'manage.json']);

Summary

PicList's advanced synchronization features provide production-ready capabilities for maintaining consistency across multiple environments:

  • Multi-backend support for GitHub, Gitee, Gitea, and WebDAV with unified API abstractions in src/main/utils/syncSettings.ts
  • Intelligent conflict resolution for gallery databases using timestamp-based merging and lastSyncTime tracking
  • Isolated temporary workspaces at $TMPDIR/piclist-sync-tmp ensuring safe database operations
  • Enterprise networking with HttpsProxyAgent support and both basic/digest WebDAV authentication
  • Incremental upload strategy that updates existing remote files before falling back to creation
  • Programmatic accessibility through RPC routes and direct TypeScript API imports

Frequently Asked Questions

PicList implements timestamp-based conflict resolution in the mergeGalleryDB() function within src/main/utils/syncSettings.ts. When merging local and remote databases, it builds a Map of all gallery items and compares their updatedAt timestamps, keeping the newer version. It also respects the settings.lastSyncTime property to ignore stale remote items that haven't changed since the last synchronization, ensuring the most recent metadata prevails.

What cloud storage providers does PicList support for configuration synchronization?

According to the source code in src/main/utils/syncSettings.ts, PicList supports four primary backend types: GitHub (via Octokit), Gitee, Gitea (self-hosted), and WebDAV (generic). The system uses a switch statement on syncConfig.type to determine which implementation of uploadLocalToRemote, downloadRemoteToLocal, and other operations to invoke, allowing seamless backend swapping without changing the high-level API.

Can PicList synchronize settings behind a corporate firewall or proxy?

Yes, PicList includes enterprise proxy support for all synchronization operations. The src/main/utils/syncSettings.ts file implements proxy handling using HttpsProxyAgent for GitHub API requests and Axios configurations for WebDAV connections. Users can specify a proxy URL in the sync configuration, enabling synchronization from restricted network environments. Additionally, WebDAV authentication supports both basic and digest methods to comply with various corporate security policies.

Is it possible to trigger PicList synchronization programmatically rather than through the GUI?

Absolutely. While the PicList UI exposes sync controls, developers can invoke synchronization directly through the internal TypeScript API. The src/main/utils/syncSettings.ts module exports functions like syncGallery(), uploadFile(), and downloadFile() that can be imported and called programmatically. Additionally, the RPC routes in src/main/events/rpc/routes/setting/configure.ts expose these capabilities to renderer processes, enabling custom scripts and plugins to trigger configuration uploads, downloads, and gallery merges without user interaction.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →