1287 lines
22 KiB
Markdown
1287 lines
22 KiB
Markdown
# Majoor API Reference
|
|
|
|
**Base Path**: `/mjr/am`
|
|
**Version**: 2.4.5
|
|
**Last Updated**: April 7, 2026
|
|
|
|
---
|
|
|
|
## Compatibility
|
|
|
|
### Versioning
|
|
- **Current API**: `/mjr/am/*` (unversioned, stable)
|
|
- **Version Alias**: `/mjr/am/v1/*` → redirects to `/mjr/am/*` (308 Permanent Redirect)
|
|
- **Legacy Alias**: `/majoor/version` → redirects to `/mjr/am/version`
|
|
|
|
### Authentication
|
|
Most endpoints require authentication when ComfyUI auth is enabled:
|
|
- **Read operations**: May work without auth (depends on configuration)
|
|
- **Write operations**: Require authentication or API token
|
|
- **CSRF Protection**: All state-changing endpoints require `X-Requested-With: XMLHttpRequest` or `X-CSRF-Token`
|
|
|
|
### API Token
|
|
For remote access or when `MAJOOR_API_TOKEN` is configured:
|
|
```
|
|
X-MJR-Token: <your-token>
|
|
# OR
|
|
Authorization: Bearer <your-token>
|
|
```
|
|
|
|
---
|
|
|
|
## Table of Contents
|
|
|
|
- [Health & Diagnostics](#health--diagnostics)
|
|
- [Settings & Configuration](#settings--configuration)
|
|
- [Search & Discovery](#search--discovery)
|
|
- [Asset Operations](#asset-operations)
|
|
- [Indexing & Scanning](#indexing--scanning)
|
|
- [Collections & Custom Roots](#collections--custom-roots)
|
|
- [Viewer & Metadata](#viewer--metadata)
|
|
- [Download & Export](#download--export)
|
|
- [Database Maintenance](#database-maintenance)
|
|
- [Utilities](#utilities)
|
|
|
|
---
|
|
|
|
## Health & Diagnostics
|
|
|
|
### Health Summary
|
|
```http
|
|
GET /mjr/am/health
|
|
```
|
|
|
|
**Response**: Extension health summary including version, status, and basic metrics.
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"version": "2.4.5",
|
|
"status": "healthy",
|
|
"indexed_count": 1234,
|
|
"scopes_available": ["output", "input", "custom", "collections"]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Health Counters
|
|
```http
|
|
GET /mjr/am/health/counters
|
|
```
|
|
|
|
**Response**: Indexed counters for all scopes.
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"output": { "count": 1000, "last_scan": "2026-02-28T10:00:00Z" },
|
|
"input": { "count": 200, "last_scan": "2026-02-28T10:00:00Z" },
|
|
"custom": { "count": 34, "last_scan": "2026-02-28T10:00:00Z" },
|
|
"collections": { "count": 5 }
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Database Health
|
|
```http
|
|
GET /mjr/am/health/db
|
|
```
|
|
|
|
**Response**: Database diagnostics including schema version, integrity status, and statistics.
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"schema_version": 7,
|
|
"integrity_check": "ok",
|
|
"page_count": 1024,
|
|
"freelist_count": 128,
|
|
"cache_size": 2000
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Runtime Configuration
|
|
```http
|
|
GET /mjr/am/config
|
|
```
|
|
|
|
**Response**: Current runtime configuration snapshot.
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"output_directory": "/path/to/output",
|
|
"index_directory": "/path/to/_mjr_index",
|
|
"media_probe_backend": "auto",
|
|
"db_timeout": 30.0,
|
|
"max_connections": 8,
|
|
"safe_mode": true,
|
|
"allow_symlinks": false
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Version Information
|
|
```http
|
|
GET /mjr/am/version
|
|
```
|
|
|
|
**Response**: Extension version and build information.
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"version": "2.4.5",
|
|
"branch": "main",
|
|
"build_date": "2026-03-29",
|
|
"python_version": "3.11.0",
|
|
"comfyui_version": "0.13.0"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Tool Status
|
|
```http
|
|
GET /mjr/am/tools/status
|
|
```
|
|
|
|
**Response**: Availability status of external tools (ExifTool, FFprobe).
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"exiftool": { "available": true, "version": "12.40" },
|
|
"ffprobe": { "available": true, "version": "6.0" },
|
|
"backend": "both"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Settings & Configuration
|
|
|
|
### Probe Backend Settings
|
|
```http
|
|
GET /mjr/am/settings/probe-backend
|
|
POST /mjr/am/settings/probe-backend
|
|
```
|
|
|
|
**GET**: Read current probe mode.
|
|
**POST**: Set probe mode.
|
|
|
|
**Request Body** (POST):
|
|
```json
|
|
{
|
|
"mode": "auto" // "auto", "exiftool", "ffprobe", "both"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"mode": "auto",
|
|
"available": ["exiftool", "ffprobe"]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Output Directory Override
|
|
```http
|
|
GET /mjr/am/settings/output-directory
|
|
POST /mjr/am/settings/output-directory
|
|
```
|
|
|
|
**GET**: Read output directory override.
|
|
**POST**: Set output directory override.
|
|
|
|
**Request Body** (POST):
|
|
```json
|
|
{
|
|
"path": "/path/to/custom/output"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"path": "/path/to/custom/output",
|
|
"exists": true,
|
|
"writable": true
|
|
}
|
|
}
|
|
```
|
|
|
|
### Index Directory Override
|
|
```http
|
|
GET /mjr/am/settings/index-directory
|
|
POST /mjr/am/settings/index-directory
|
|
```
|
|
|
|
**GET**: Read the current index directory path.
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"index_directory": "/path/to/_mjr_index"
|
|
}
|
|
}
|
|
```
|
|
|
|
**POST**: Set a new index directory path.
|
|
|
|
> Requires write access (loopback or valid `X-MJR-Token`).
|
|
|
|
**Request Body** (POST):
|
|
```json
|
|
{
|
|
"index_directory": "/path/to/local/mjr_index"
|
|
}
|
|
```
|
|
|
|
Send an empty string to clear the override and revert to the default (`<output>/_mjr_index/`):
|
|
```json
|
|
{
|
|
"index_directory": ""
|
|
}
|
|
```
|
|
|
|
**Response** (POST):
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"index_directory": "/path/to/local/mjr_index",
|
|
"requires_restart": true
|
|
}
|
|
}
|
|
```
|
|
|
|
The new path is persisted to the `.mjr_index_directory_override` sidecar file and the in-process environment variables. The change takes effect after ComfyUI is restarted.
|
|
|
|
**Error codes**:
|
|
|
|
| Code | Meaning |
|
|
|---|---|
|
|
| `INVALID_INPUT` | Path exists but is a file, not a directory |
|
|
| `INVALID_INPUT` | Path was given as a non-empty string but the parent directory does not exist |
|
|
| `DB_ERROR` | Sidecar file could not be written |
|
|
|
|
---
|
|
|
|
### Metadata Fallback Toggles
|
|
```http
|
|
GET /mjr/am/settings/metadata-fallback
|
|
POST /mjr/am/settings/metadata-fallback
|
|
```
|
|
|
|
**GET**: Read fallback toggles for metadata extraction.
|
|
**POST**: Set fallback toggles.
|
|
|
|
**Request Body** (POST):
|
|
```json
|
|
{
|
|
"image": true, // Use internal parser if ExifTool fails
|
|
"media": true // Use hachoir if ffprobe unavailable
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"image": true,
|
|
"media": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Search & Discovery
|
|
|
|
### Search with Filters
|
|
```http
|
|
GET /mjr/am/search
|
|
```
|
|
|
|
**Query Parameters**:
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `q` | string | Search query (full-text) |
|
|
| `scope` | string | Scope: `output`, `input`, `custom`, `collections` |
|
|
| `root_id` | string | Custom root ID (for custom scope) |
|
|
| `collection_id` | string | Collection ID (for collections scope) |
|
|
| `kind` | string | File kind: `image`, `video`, `audio`, `model3d`, `all` |
|
|
| `min_rating` | integer | Minimum rating (0-5) |
|
|
| `workflow` | boolean | Filter by workflow presence |
|
|
| `date_from` | string | Start date (ISO 8601) |
|
|
| `date_to` | string | End date (ISO 8601) |
|
|
| `size_from` | integer | Minimum file size (bytes) |
|
|
| `size_to` | integer | Maximum file size (bytes) |
|
|
| `width_from` | integer | Minimum image width |
|
|
| `width_to` | integer | Maximum image width |
|
|
| `height_from` | integer | Minimum image height |
|
|
| `height_to` | integer | Maximum image height |
|
|
| `sort` | string | Sort field: `relevance`, `name`, `date`, `size`, `rating` |
|
|
| `order` | string | Sort order: `asc`, `desc` |
|
|
| `page` | integer | Page number (1-based) |
|
|
| `page_size` | integer | Items per page (default: 50) |
|
|
| `hide_png_siblings` | boolean | Hide PNGs when video exists |
|
|
|
|
**Example**:
|
|
```http
|
|
GET /mjr/am/search?q=fantasy&scope=output&kind=image&min_rating=4&sort=date&order=desc&page=1&page_size=50
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"total": 150,
|
|
"page": 1,
|
|
"page_size": 50,
|
|
"total_pages": 3,
|
|
"items": [
|
|
{
|
|
"id": "asset_123",
|
|
"filename": "fantasy_character.png",
|
|
"path": "/path/to/output/fantasy_character.png",
|
|
"type": "image",
|
|
"size": 2048576,
|
|
"width": 1024,
|
|
"height": 1536,
|
|
"rating": 5,
|
|
"tags": ["fantasy", "character"],
|
|
"created_at": "2026-02-28T10:00:00Z",
|
|
"metadata": {
|
|
"prompt": "A fantasy character...",
|
|
"model": "SDXL",
|
|
"steps": 30
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### List Assets (Paginated)
|
|
```http
|
|
GET /mjr/am/list
|
|
```
|
|
|
|
**Query Parameters**: Same as search, but without `q` parameter.
|
|
|
|
**Purpose**: List assets without full-text search (faster for browsing).
|
|
|
|
---
|
|
|
|
### Asset Details
|
|
```http
|
|
GET /mjr/am/asset/{asset_id}
|
|
```
|
|
|
|
**Response**: Full asset details including metadata.
|
|
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"id": "asset_123",
|
|
"filename": "fantasy_character.png",
|
|
"path": "/path/to/output/fantasy_character.png",
|
|
"type": "image",
|
|
"extension": "png",
|
|
"size": 2048576,
|
|
"width": 1024,
|
|
"height": 1536,
|
|
"rating": 5,
|
|
"tags": ["fantasy", "character"],
|
|
"created_at": "2026-02-28T10:00:00Z",
|
|
"modified_at": "2026-02-28T10:00:00Z",
|
|
"metadata": {
|
|
"prompt": "A fantasy character...",
|
|
"negative_prompt": "ugly, blurry",
|
|
"model": "SDXL",
|
|
"sampler": "DPM++ 2M Karras",
|
|
"steps": 30,
|
|
"cfg_scale": 7.0,
|
|
"seed": 123456789,
|
|
"workflow": { ... }
|
|
},
|
|
"thumbnails": {
|
|
"small": "/mjr/am/thumbnail/asset_123?size=small",
|
|
"medium": "/mjr/am/thumbnail/asset_123?size=medium",
|
|
"large": "/mjr/am/thumbnail/asset_123?size=large"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Metadata Lookup
|
|
```http
|
|
GET /mjr/am/metadata
|
|
```
|
|
|
|
**Query Parameters**:
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `type` | string | Scope type: `output`, `input`, `custom` |
|
|
| `filename` | string | Filename |
|
|
| `subfolder` | string | Subfolder path (optional) |
|
|
| `root_id` | string | Custom root ID (for custom scope) |
|
|
|
|
**Example**:
|
|
```http
|
|
GET /mjr/am/metadata?type=output&filename=image.png&subfolder=2026-02-28
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"filename": "image.png",
|
|
"path": "/path/to/output/2026-02-28/image.png",
|
|
"metadata": { ... }
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Asset Operations
|
|
|
|
### Update Rating
|
|
```http
|
|
POST /mjr/am/asset/rating
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_id": "asset_123",
|
|
"rating": 5 // 0-5
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"rating": 5,
|
|
"synced_to_file": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Update Tags
|
|
```http
|
|
POST /mjr/am/asset/tags
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_id": "asset_123",
|
|
"tags": ["fantasy", "character", "sdxl"]
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"tags": ["fantasy", "character", "sdxl"],
|
|
"synced_to_file": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Rename Asset
|
|
```http
|
|
POST /mjr/am/asset/rename
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_id": "asset_123",
|
|
"new_filename": "new_name.png"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"old_path": "/path/to/old_name.png",
|
|
"new_path": "/path/to/new_name.png"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: Requires `MAJOOR_ALLOW_RENAME=1` if Safe Mode is enabled.
|
|
|
|
---
|
|
|
|
### Delete Single Asset
|
|
```http
|
|
POST /mjr/am/asset/delete
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_id": "asset_123"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"deleted": true,
|
|
"path": "/path/to/deleted_file.png"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: Requires `MAJOOR_ALLOW_DELETE=1` if Safe Mode is enabled.
|
|
|
|
---
|
|
|
|
### Bulk Delete Assets
|
|
```http
|
|
POST /mjr/am/assets/delete
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_ids": ["asset_123", "asset_124", "asset_125"]
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"deleted_count": 3,
|
|
"deleted_ids": ["asset_123", "asset_124", "asset_125"],
|
|
"failed": []
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: Requires `MAJOOR_ALLOW_DELETE=1` if Safe Mode is enabled.
|
|
|
|
---
|
|
|
|
### Open in Folder
|
|
```http
|
|
POST /mjr/am/open-in-folder
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_id": "asset_123"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"path": "/path/to/output",
|
|
"opened": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: Requires `MAJOOR_ALLOW_OPEN_IN_FOLDER=1` if Safe Mode is enabled.
|
|
|
|
---
|
|
|
|
### Stage to Input
|
|
```http
|
|
POST /mjr/am/stage-to-input
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_id": "asset_123"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"staged_path": "/path/to/input/staged_file.png",
|
|
"staged": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Purpose**: Copy/link asset to ComfyUI input directory for workflow use.
|
|
|
|
---
|
|
|
|
## Indexing & Scanning
|
|
|
|
### Scan Scope/Root
|
|
```http
|
|
POST /mjr/am/scan
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"scope": "output", // "output", "input", "custom"
|
|
"root_id": null, // Custom root ID (for custom scope)
|
|
"incremental": true, // Incremental scan (default)
|
|
"force": false // Force full rescan
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"scan_id": "scan_123",
|
|
"scope": "output",
|
|
"status": "started",
|
|
"estimated_duration_ms": 5000
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: Scan runs in background. Status available via health endpoints.
|
|
|
|
---
|
|
|
|
### Index Explicit Files
|
|
```http
|
|
POST /mjr/am/index-files
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"files": [
|
|
{
|
|
"filename": "image.png",
|
|
"subfolder": "2026-02-28",
|
|
"type": "output"
|
|
}
|
|
],
|
|
"origin": "generation" // "generation", "manual", "import"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"indexed_count": 1,
|
|
"failed": []
|
|
}
|
|
}
|
|
```
|
|
|
|
**Purpose**: Index specific files (used for real-time generation tracking).
|
|
|
|
---
|
|
|
|
### Reset Index
|
|
```http
|
|
POST /mjr/am/index/reset
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"scope": "output", // Scope to reset
|
|
"clear_assets": true, // Clear asset records
|
|
"clear_metadata": true, // Clear metadata cache
|
|
"clear_fts": true, // Clear full-text search index
|
|
"clear_journal": true // Clear scan journal
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"scope": "output",
|
|
"reset": true,
|
|
"rescan_triggered": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Collections & Custom Roots
|
|
|
|
### List Collections
|
|
```http
|
|
GET /mjr/am/collections
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"collections": [
|
|
{
|
|
"id": "collection_123",
|
|
"name": "Best Characters",
|
|
"item_count": 25,
|
|
"created_at": "2026-02-28T10:00:00Z",
|
|
"modified_at": "2026-02-28T12:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Create/Update Collection
|
|
```http
|
|
POST /mjr/am/collections/create
|
|
POST /mjr/am/collections/update
|
|
```
|
|
|
|
**Request Body** (Create):
|
|
```json
|
|
{
|
|
"name": "Best Characters",
|
|
"items": [
|
|
{
|
|
"asset_id": "asset_123",
|
|
"scope": "output"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
**Request Body** (Update):
|
|
```json
|
|
{
|
|
"collection_id": "collection_123",
|
|
"name": "Updated Name",
|
|
"items": [...],
|
|
"add_items": [...], // Items to add
|
|
"remove_items": [...] // Items to remove
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"collection_id": "collection_123",
|
|
"name": "Updated Name",
|
|
"item_count": 30
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Delete Collection
|
|
```http
|
|
POST /mjr/am/collections/delete
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"collection_id": "collection_123"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"collection_id": "collection_123",
|
|
"deleted": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: Does not delete assets, only the collection definition.
|
|
|
|
---
|
|
|
|
### List Custom Roots
|
|
```http
|
|
GET /mjr/am/custom-roots
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"roots": [
|
|
{
|
|
"id": "root_123",
|
|
"path": "/path/to/custom/dir",
|
|
"name": "Custom Directory",
|
|
"added_at": "2026-02-28T10:00:00Z"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Add Custom Root
|
|
```http
|
|
POST /mjr/am/custom-roots/add
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"path": "/path/to/custom/dir",
|
|
"name": "Custom Directory"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"root_id": "root_123",
|
|
"path": "/path/to/custom/dir",
|
|
"added": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Remove Custom Root
|
|
```http
|
|
POST /mjr/am/custom-roots/remove
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"root_id": "root_123"
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"root_id": "root_123",
|
|
"removed": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Viewer & Metadata
|
|
|
|
### Viewer Info
|
|
```http
|
|
GET /mjr/am/viewer/info
|
|
```
|
|
|
|
**Query Parameters**:
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `asset_id` | string | Asset ID |
|
|
|
|
**Example**:
|
|
```http
|
|
GET /mjr/am/viewer/info?asset_id=asset_123
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"asset_id": "asset_123",
|
|
"filename": "fantasy_character.png",
|
|
"type": "image",
|
|
"width": 1024,
|
|
"height": 1536,
|
|
"metadata": {
|
|
"prompt": "A fantasy character...",
|
|
"model": "SDXL",
|
|
"workflow_minimap": { ... }
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Download & Export
|
|
|
|
### Download Asset
|
|
```http
|
|
GET /mjr/am/download
|
|
```
|
|
|
|
**Query Parameters**:
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `asset_id` | string | Asset ID |
|
|
| `filename` | string | Filename (for direct download) |
|
|
| `type` | string | Scope type |
|
|
| `subfolder` | string | Subfolder path |
|
|
|
|
**Example**:
|
|
```http
|
|
GET /mjr/am/download?asset_id=asset_123
|
|
```
|
|
|
|
**Response**: File stream with appropriate Content-Type and Content-Disposition headers.
|
|
|
|
---
|
|
|
|
### Create Batch ZIP
|
|
```http
|
|
POST /mjr/am/batch-zip
|
|
```
|
|
|
|
**Request Body**:
|
|
```json
|
|
{
|
|
"asset_ids": ["asset_123", "asset_124", "asset_125"]
|
|
}
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"token": "zip_token_abc123",
|
|
"expires_at": "2026-02-28T11:00:00Z",
|
|
"download_url": "/mjr/am/batch-zip/zip_token_abc123"
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Download Batch ZIP
|
|
```http
|
|
GET /mjr/am/batch-zip/{token}
|
|
```
|
|
|
|
**Response**: ZIP file stream containing all requested assets.
|
|
|
|
---
|
|
|
|
## Database Maintenance
|
|
|
|
### Optimize Database
|
|
```http
|
|
POST /mjr/am/db/optimize
|
|
```
|
|
|
|
**Purpose**: Run `PRAGMA optimize` and `ANALYZE` for performance.
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"optimized": true,
|
|
"duration_ms": 150
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Cleanup Case Duplicates
|
|
```http
|
|
POST /mjr/am/db/cleanup-case-duplicates
|
|
```
|
|
|
|
**Purpose**: Remove historical path-case duplicates (Windows-specific).
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"duplicates_removed": 5,
|
|
"kept_canonical": 100
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Force-Delete Database
|
|
```http
|
|
POST /mjr/am/db/force-delete
|
|
```
|
|
|
|
**Purpose**: Emergency recovery for corrupted databases.
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"deleted": true,
|
|
"reinitialized": true,
|
|
"rescan_triggered": true
|
|
}
|
|
}
|
|
```
|
|
|
|
**Note**: This endpoint bypasses normal DB-dependent security checks for emergency recovery.
|
|
|
|
---
|
|
|
|
## Utilities
|
|
|
|
### Date Histogram
|
|
```http
|
|
GET /mjr/am/date-histogram
|
|
```
|
|
|
|
**Query Parameters**:
|
|
| Parameter | Type | Description |
|
|
|-----------|------|-------------|
|
|
| `month` | string | Month in YYYY-MM format |
|
|
| `scope` | string | Scope type |
|
|
|
|
**Example**:
|
|
```http
|
|
GET /mjr/am/date-histogram?month=2026-02&scope=output
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"month": "2026-02",
|
|
"days": [
|
|
{ "date": "2026-02-01", "count": 50 },
|
|
{ "date": "2026-02-02", "count": 75 },
|
|
...
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
**Purpose**: Calendar histogram for date-based filtering UI.
|
|
|
|
---
|
|
|
|
### Duplicate Alerts
|
|
```http
|
|
GET /mjr/am/duplicates/alerts
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"duplicate_groups": [
|
|
{
|
|
"filename": "image.png",
|
|
"paths": [
|
|
"/path/to/output/image.png",
|
|
"/path/to/output/subfolder/image.png"
|
|
],
|
|
"count": 2
|
|
}
|
|
],
|
|
"total_groups": 5,
|
|
"total_duplicates": 10
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Releases Information
|
|
```http
|
|
GET /mjr/am/releases
|
|
```
|
|
|
|
**Response**:
|
|
```json
|
|
{
|
|
"ok": true,
|
|
"data": {
|
|
"current_version": "2.4.5",
|
|
"branch": "main",
|
|
"latest_release": {
|
|
"version": "2.4.5",
|
|
"date": "2026-04-10",
|
|
"download_url": "https://github.com/MajoorWaldi/ComfyUI-Majoor-AssetsManager/releases/tag/v2.4.5"
|
|
},
|
|
"branches_available": ["main", "dev"],
|
|
"tags_available": ["v2.4.5", "v2.4.4", "v2.4.3", "v2.4.2"]
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Security Notes
|
|
|
|
### CSRF Protection
|
|
All state-changing endpoints (POST, PUT, PATCH, DELETE) require:
|
|
- `X-Requested-With: XMLHttpRequest` header, OR
|
|
- `X-CSRF-Token` header with valid token
|
|
|
|
### Authentication
|
|
When ComfyUI auth is enabled:
|
|
- Write operations require authenticated user
|
|
- API token can be used for remote access
|
|
- Token sent via `X-MJR-Token` or `Authorization: Bearer`
|
|
|
|
### Safe Mode
|
|
When Safe Mode is enabled (default):
|
|
- Delete operations require `MAJOOR_ALLOW_DELETE=1`
|
|
- Rename operations require `MAJOOR_ALLOW_RENAME=1`
|
|
- Open in folder requires `MAJOOR_ALLOW_OPEN_IN_FOLDER=1`
|
|
|
|
### Rate Limiting
|
|
Expensive endpoints are rate-limited:
|
|
- Search: 10 requests/minute per client
|
|
- Scan: 5 requests/minute per client
|
|
- Batch ZIP: 3 requests/minute per client
|
|
- Metadata: 20 requests/minute per client
|
|
|
|
Client identity based on IP address (or `X-Forwarded-For` from trusted proxies).
|
|
|
|
---
|
|
|
|
## Error Responses
|
|
|
|
### Standard Error Format
|
|
```json
|
|
{
|
|
"ok": false,
|
|
"error": {
|
|
"code": "ERROR_CODE",
|
|
"message": "Human-readable error message",
|
|
"details": { ... } // Optional additional context
|
|
}
|
|
}
|
|
```
|
|
|
|
### Common Error Codes
|
|
| Code | HTTP Status | Description |
|
|
|------|-------------|-------------|
|
|
| `AUTH_REQUIRED` | 401 | Authentication required |
|
|
| `FORBIDDEN` | 403 | Operation not allowed (Safe Mode) |
|
|
| `NOT_FOUND` | 404 | Resource not found |
|
|
| `INVALID_REQUEST` | 400 | Invalid request body/parameters |
|
|
| `RATE_LIMITED` | 429 | Too many requests |
|
|
| `DB_ERROR` | 500 | Database error |
|
|
| `FILE_SYSTEM_ERROR` | 500 | File system error |
|
|
| `TOOL_UNAVAILABLE` | 503 | External tool not available |
|
|
|
|
---
|
|
|
|
## WebSocket Events
|
|
|
|
### Real-Time Updates
|
|
The extension emits ComfyUI API events for real-time updates:
|
|
|
|
- `mjr-asset-added`: New asset indexed
|
|
- `mjr-asset-updated`: Asset metadata updated
|
|
- `mjr-scan-complete`: Scan operation completed
|
|
- `mjr-enrichment-status`: Metadata enrichment status
|
|
- `mjr-db-restore-status`: Database restore status
|
|
|
|
**Example** (Frontend):
|
|
```javascript
|
|
api.addEventListener("mjr-asset-added", (event) => {
|
|
const asset = event.detail;
|
|
// Update UI with new asset
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
*API Reference Version: 2.0*
|
|
*Last Updated: April 5, 2026*
|
|
*Compatible with Majoor Assets Manager v2.4.4+*
|