1.6.6
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
# noEmbryo Nodes
|
||||
A diverse set of nodes for ComfyUI.
|
||||
- [Json Prompt Loader](#json-prompt-loader)
|
||||
- [Load Image (from path)](#load-image-from-path)
|
||||
- [Resolution Scale](#resolution-scale)
|
||||
- [Regex Text Chopper](#regex-text-chopper)
|
||||
- [H3 Motion Context Clip Stitcher](#h3-motion-context-clip-stitcher)
|
||||
- [H3 Motion Context Clip Purge](#h3-motion-context-clip-purge)
|
||||
- [Auto Save Workflow](#auto-save-workflow)
|
||||
- [PromptTermList (1-6)](#prompttermlist-1-6)
|
||||
|
||||
@@ -142,6 +145,23 @@ No quality loss, like when trying to concatenate encoded videos.
|
||||
- **frame_count**: The total number of frames
|
||||
- **report**: Logging of some of the node's actions
|
||||
|
||||
---
|
||||
## H3 Motion Context Clip Purge
|
||||

|
||||
Deletes the numbered `h3_motion_context_av_v1` clip archive files at the root of a folder (default: `h3_context`)
|
||||
Only files matching the pattern are removed; sub-folders and everything inside them are left untouched.
|
||||
|
||||
- **Controls**
|
||||
- **mode**: Purge (Enabled): delete the matching files.
|
||||
Preview (dry run, Disabled): delete nothing; the report just lists the files that would be deleted.
|
||||
- **folder** is the folder whose root-level clip archives will be deleted.
|
||||
Absolute paths and paths relative to ComfyUI/output are accepted.
|
||||
- **pattern** is the filename glob. Only root-level FILES matching this pattern are deleted.
|
||||
Sub-folders are never touched.
|
||||
- **Outputs**
|
||||
- **report**: Shows the actions of the node.
|
||||
|
||||
|
||||
|
||||
---
|
||||
## Auto Save Workflow
|
||||
|
||||
@@ -19,12 +19,14 @@ from server import PromptServer
|
||||
|
||||
|
||||
def _is_url(s) -> bool:
|
||||
"""Return True if s looks like an HTTP(S) URL."""
|
||||
""" Return True if s looks like an HTTP(S) URL.
|
||||
"""
|
||||
# noinspection HttpUrlsUsage
|
||||
return isinstance(s, str) and (s.startswith("http://") or s.startswith("https://"))
|
||||
|
||||
|
||||
def _fetch_url_bytes(url: str, timeout: float = 30.0) -> bytes:
|
||||
"""Download the bytes of a URL. Raises on any network/HTTP problem.
|
||||
""" Download the bytes of a URL. Raises on any network/HTTP problem.
|
||||
|
||||
Embedded Python distributions (StabilityMatrix, ComfyUI portable, ...) often
|
||||
ship with a missing or outdated CA bundle, causing CERTIFICATE_VERIFY_FAILED
|
||||
@@ -46,6 +48,7 @@ def _fetch_url_bytes(url: str, timeout: float = 30.0) -> bytes:
|
||||
|
||||
# Strategy 2: use certifi's CA bundle if it's installed.
|
||||
try:
|
||||
# noinspection PyUnresolvedReferences
|
||||
import certifi
|
||||
ctx = ssl.create_default_context(cafile=certifi.where())
|
||||
opener = build_opener(HTTPSHandler(context=ctx))
|
||||
@@ -66,6 +69,7 @@ def _fetch_url_bytes(url: str, timeout: float = 30.0) -> bytes:
|
||||
"downloads without certificate validation. Consider installing/"
|
||||
"updating the 'certifi' package for secure downloads.")
|
||||
_ssl_warning_shown = True
|
||||
# noinspection PyUnresolvedReferences,PyProtectedMember
|
||||
ctx = ssl._create_unverified_context()
|
||||
opener = build_opener(HTTPSHandler(context=ctx))
|
||||
with opener.open(req, timeout=timeout) as resp:
|
||||
|
||||
@@ -4,17 +4,18 @@ from os.path import realpath, join, dirname, isabs, splitext, basename
|
||||
from datetime import datetime
|
||||
import folder_paths
|
||||
from .load_image_from_path import LoadImageFromPathEnhanced
|
||||
from .stitcher import H3MotionContextClipStitcher, H3ContextLatentConverter
|
||||
from .stitcher import (H3MotionContextClipStitcher, H3ContextLatentConverter,
|
||||
H3MotionContextClipPurge)
|
||||
|
||||
MANIFEST = {"name": "noEmbryo Nodes",
|
||||
"version": (1, 6, 5),
|
||||
"version": (1, 6, 6),
|
||||
"author": "noEmbryo",
|
||||
"project": "https://github.com/noembryo/ComfyUI-noEmbryo",
|
||||
"description": "Nodes for ComfyUI",
|
||||
"license": "MIT",
|
||||
}
|
||||
__author__ = "noEmbryo"
|
||||
__version__ = "1.6.5"
|
||||
__version__ = "1.6.6"
|
||||
|
||||
LISTS_PATH = join(dirname(realpath(__file__)), "TermLists")
|
||||
|
||||
@@ -481,6 +482,7 @@ NODE_CLASS_MAPPINGS = {f"JsonPromptLoader -{__author__}": JsonPromptLoader,
|
||||
f"Auto Save Workflow -{__author__}": AutoSaveWorkflow,
|
||||
f"Load Image (from path) -{__author__}": LoadImageFromPathEnhanced,
|
||||
f"H3MotionContextClipStitcher -{__author__}": H3MotionContextClipStitcher,
|
||||
f"H3MotionContextClipPurge -{__author__}": H3MotionContextClipPurge,
|
||||
f"H3ContextLatentConverter -{__author__}": H3ContextLatentConverter,
|
||||
"PromptTermList1": PromptTermList1,
|
||||
"PromptTermList2": PromptTermList2,
|
||||
@@ -496,6 +498,7 @@ NODE_DISPLAY_NAME_MAPPINGS = {f"JsonPromptLoader -{__author__}": f"Json Prompt L
|
||||
f"Auto Save Workflow -{__author__}": f"Auto Save Workflow /{__author__}",
|
||||
f"Load Image (from path) -{__author__}": f"Load Image (from path) /{__author__}",
|
||||
f"H3MotionContextClipStitcher -{__author__}": f"H3 Motion Context Clip Stitcher /{__author__}",
|
||||
f"H3MotionContextClipPurge -{__author__}": f"H3 Motion Context Clip Purge /{__author__}",
|
||||
f"H3ContextLatentConverter -{__author__}": f"H3 Context Latent Converter /{__author__}",
|
||||
"PromptTermList1": f"PromptTermList 1 /{__author__}",
|
||||
"PromptTermList2": f"PromptTermList 2 /{__author__}",
|
||||
|
||||
+3
-2
@@ -5,13 +5,14 @@ A collection of nodes for ComyUI. \n
|
||||
* "Load Image (from path)" lets you load an image from any path in your computer or a URL, and use a selection rectangle at the preview to crop it. It can also
|
||||
limit the output's size in megapixels. \n
|
||||
* "H3 Motion Context Clip Stitcher" concatenates H3 Motion Context clip archives. \n
|
||||
* "H3 Motion Context Clip Purge" clears all H3 Motion Context clip archives. \n
|
||||
* "JsonPromptLoader" enhances a propt using a .json file with `item:prompt` pairs. \n
|
||||
* "Resolution Scale" resizes an image using pixels or scale factor. \n
|
||||
* "Regex Text Chopper" cuts text based on regex. \n
|
||||
* "PromptTermList (1-6)" nodes to help with the creation of Prompts. \n
|
||||
* "Auto Save Workflow" can save the current workflow to a .json file automatically. \n
|
||||
"""
|
||||
version = "1.6.5"
|
||||
version = "1.6.6"
|
||||
license = {text = "MIT License"}
|
||||
|
||||
[project.urls]
|
||||
@@ -20,5 +21,5 @@ Repository = "https://github.com/noembryo/ComfyUI-noEmbryo"
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "noembryo"
|
||||
DisplayName = "noEmbryo"
|
||||
DisplayName = "noEmbryoNodes"
|
||||
Icon = "https://iili.io/JmSdmAJ.png"
|
||||
|
||||
+90
-2
@@ -9,6 +9,7 @@ into Motion Context.
|
||||
The archive format is the sampler output, and this node is a final-media assembly tool.
|
||||
"""
|
||||
|
||||
import fnmatch
|
||||
import glob
|
||||
import logging
|
||||
import os
|
||||
@@ -134,8 +135,7 @@ def _decode_audio(audio_vae, audio_latent):
|
||||
audio = audio_vae.decode(audio_latent)
|
||||
# Current ComfyUI audio VAE returns [B,L,C]. Convert to [B,C,L].
|
||||
if audio.ndim != 3:
|
||||
raise RuntimeError("H3 audio VAE returned unexpected shape %s"
|
||||
% (tuple(audio.shape),))
|
||||
raise RuntimeError("H3 audio VAE returned unexpected shape %s" % (tuple(images.shape),))
|
||||
audio = audio.movedim(-1, 1)
|
||||
sr = int(getattr(audio_vae, "audio_sample_rate_output",
|
||||
getattr(audio_vae, "audio_sample_rate", 32000)))
|
||||
@@ -574,12 +574,100 @@ class H3ContextLatentConverter:
|
||||
return (converted,)
|
||||
|
||||
|
||||
class H3MotionContextClipPurge:
|
||||
""" Delete the saved H3 Motion Context clip archive files from a folder.
|
||||
"""
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {"required": {"mode": ("BOOLEAN", {"default": True,
|
||||
"label_on": "Purge", "label_off": "Preview (dry run)",
|
||||
"tooltip": "Purge (Enabled): delete the matching files.\n"
|
||||
"Preview (dry run, Disabled): delete nothing; the report "
|
||||
"just lists the files that would be deleted."}),
|
||||
"folder": ("STRING", {"default": "h3_context",
|
||||
"tooltip": "Folder whose root-level clip archives will be deleted.\n"
|
||||
"Absolute paths and paths relative to ComfyUI/output are "
|
||||
"accepted."}),
|
||||
"pattern": ("STRING", {"default": "clip_*.safetensors",
|
||||
"tooltip": "Filename glob. Only root-level FILES matching this "
|
||||
"pattern are deleted.\nSub-folders are never touched."}), },
|
||||
"hidden": {"mode": "BOOLEAN"}}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("report",)
|
||||
FUNCTION = "purge"
|
||||
CATEGORY = "noEmbryo"
|
||||
OUTPUT_NODE = True
|
||||
DESCRIPTION = ("Deletes the numbered h3_motion_context_av_v1 clip archive files "
|
||||
"at the root of a folder (default: h3_context).\n"
|
||||
"Purge (Enabled): deletes the files.\n"
|
||||
"Preview (Disabled): dry run - the report only lists what would "
|
||||
"be deleted.\nOnly files matching the pattern are removed; "
|
||||
"sub-folders and everything inside them are left untouched.")
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@classmethod
|
||||
def IS_CHANGED(cls, mode, folder, pattern):
|
||||
return float("NaN")
|
||||
|
||||
@staticmethod
|
||||
def purge(mode, folder, pattern):
|
||||
d = _resolve_folder(folder)
|
||||
pattern = (pattern or "clip_*.safetensors").strip()
|
||||
|
||||
doomed = []
|
||||
for entry in os.scandir(d):
|
||||
if entry.is_file(follow_symlinks=False) and not entry.is_dir():
|
||||
if fnmatch.fnmatch(entry.name, pattern):
|
||||
doomed.append((entry.name, entry.stat().st_size))
|
||||
|
||||
if not mode: # Preview (dry run)
|
||||
lines = ["H3 clip purge (DRY RUN) in %s - nothing was deleted:" % d]
|
||||
lines += [" would delete: %s (%s)" % (name, _fmt_size(size))
|
||||
for name, size in doomed] or [" no matching files."]
|
||||
lines.append("TOTAL: %d file(s), %s" %
|
||||
(len(doomed), _fmt_size(sum(s for _, s in doomed))))
|
||||
report = "\n".join(lines)
|
||||
log_.info(report)
|
||||
return (report,)
|
||||
|
||||
deleted = 0
|
||||
freed = 0
|
||||
lines = ["H3 clip purge in %s:" % d]
|
||||
for name, size in doomed:
|
||||
try:
|
||||
os.remove(os.path.join(d, name))
|
||||
deleted += 1
|
||||
freed += size
|
||||
lines.append(" deleted: %s (%s)" % (name, _fmt_size(size)))
|
||||
except OSError as e:
|
||||
lines.append(" FAILED to delete %s: %s" % (name, e))
|
||||
if not deleted and not doomed:
|
||||
lines.append(" no matching files.")
|
||||
lines.append("TOTAL: deleted %d file(s), freed %s" %
|
||||
(deleted, _fmt_size(freed)))
|
||||
report = "\n".join(lines)
|
||||
log_.info(report)
|
||||
return (report,)
|
||||
|
||||
|
||||
def _fmt_size(num_bytes):
|
||||
size = float(num_bytes)
|
||||
for unit in ("B", "KiB", "MiB", "GiB"):
|
||||
if size < 1024.0:
|
||||
return "%.1f %s" % (size, unit)
|
||||
size /= 1024.0
|
||||
return "%.1f TiB" % size
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"H3MotionContextClipStitcher": H3MotionContextClipStitcher,
|
||||
"H3ContextLatentConverter": H3ContextLatentConverter,
|
||||
"H3MotionContextClipPurge": H3MotionContextClipPurge,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"H3MotionContextClipStitcher": "H3 Motion Context Clip Stitcher",
|
||||
"H3ContextLatentConverter": "H3 Context Latent Converter",
|
||||
"H3MotionContextClipPurge": "H3 Motion Context Clip Purge",
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 31 KiB |
Reference in New Issue
Block a user