Adds a declarative blueprint.{yaml,json} manifest layer on top of the existing dynamic-module plugin loader. Each plugin can now ship as a self-contained package with a manifest describing name, version, author, type, entrypoint class, and capabilities. The legacy flat .py plugin format remains fully supported.
Manifest schema v1 with fields: schema_version, name (slug), version (semver), author, type (metadata_extractor), entrypoint.{module,class}, optional capabilities/tags/license/homepage/description/min_majoor_version. Path-traversal and module-name injection are rejected at parse time. YAML manifests require PyYAML (already shipped by ComfyUI core); JSON manifests need no extra deps.
Loader: PluginLoader.discover_plugins now treats subdirectories with a blueprint manifest as blueprint packages (taking precedence over plain Python-package scanning). New PluginLoader.blueprints property and get_stats[blueprints] field expose loaded manifests for listing endpoints.
Migrated bundled examples to blueprint layout: plugins/examples/wanvideo/, plugins/examples/custom_node_template/, plugins/examples/rgthree/ (YAML variant).
Tests: 11 new tests in tests/features/test_blueprint_plugins.py covering manifest parsing edge cases (bad name, bad semver, unknown type, path traversal, schema mismatch), YAML support, discovery skipping invalid manifests, and loader integration including a missing-entrypoint warning path.
54 lines
1.5 KiB
Python
54 lines
1.5 KiB
Python
"""rgthree custom-node metadata extractor (Blueprint example).
|
|
|
|
This is a minimal scaffold provided to illustrate how a YAML-manifest
|
|
blueprint plugin is shaped. It returns an empty success result and is
|
|
intended as a copy-and-modify starting point — extend the ``extract``
|
|
method with the actual rgthree parsing logic before relying on it.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import logging
|
|
|
|
from mjr_am_backend.features.metadata.plugin_system.base import (
|
|
ExtractionResult,
|
|
ExtractorMetadata,
|
|
MetadataExtractorPlugin,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class RgthreeExtractor(MetadataExtractorPlugin):
|
|
"""Skeleton extractor for rgthree-flavored ComfyUI workflows."""
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return "rgthree_extractor"
|
|
|
|
@property
|
|
def supported_extensions(self) -> list[str]:
|
|
return [".png", ".webp"]
|
|
|
|
@property
|
|
def priority(self) -> int:
|
|
return 50
|
|
|
|
@property
|
|
def metadata(self) -> ExtractorMetadata:
|
|
return ExtractorMetadata(
|
|
name=self.name,
|
|
version="0.1.0",
|
|
author="Majoor Assets Manager",
|
|
description="Skeleton extractor for rgthree custom nodes.",
|
|
)
|
|
|
|
async def extract(self, filepath: str) -> ExtractionResult:
|
|
# Replace this stub with the real rgthree parsing logic.
|
|
return ExtractionResult(
|
|
success=True,
|
|
data={},
|
|
extractor_name=self.name,
|
|
confidence=0.0,
|
|
)
|