- Updated SequentialAudioBatchLoader to dynamically evaluate global_has_more_batches rather than statically assigning False.
- Refactored IncrementalVideoStitcher to calculate is_absolute_final only when both the current chunk is complete and there are no more batches in queue.
- Updated return blocks in stitch method to propagate new is_absolute_final logic.
Adds a new boolean output `IS_ABSOLUTE_FINAL` to the `IncrementalVideoStitcher` node.
This determines if the current generation cycle is the very last one across all processed batches, by checking `global_has_more_batches` from `loop.py`. Updates the tuple structures and node signatures to reflect this new return type.
Added `IS_CHANGED` class methods to calculation nodes (`AutoLoopCalculator`, `AutoLoopCalculatorTTS`, `AutoLoopCalculatorWan`, `AutoLoopCalculatorLTX`, `AutoLoopCalculatorTTSBatch`) and `LazySessionCache` to force ComfyUI to re-evaluate them continuously, resolving a false positive cache issue that prevented global Python state variables from updating correctly across batch boundaries.
Added input validations (`source_frame_count <= 0` or `target_frames_per_loop <= 0`) to `AutoLoopCalculatorLTX` (in `loop.py`), and `AutoLoopCalculator`, `AutoLoopCalculatorWan` (in `video.py`). When conditions are met, a safe default is returned to prevent math domain errors. Also included a new comprehensive unit test suite in `tests/test_loop_calculator.py`.
- Introduce `global_step_by_chunk` ghost variable initialized to `False` in `loop.py`
- Set `loop.global_step_by_chunk = True` in `AutoLoopCalculatorTTS` to indicate chunk mode
- Reset `loop.global_step_by_chunk = False` in video calculators (`AutoLoopCalculator`, `AutoLoopCalculatorWan`, `AutoLoopCalculatorLTX`) to ensure state resets
- Update `SessionImageSender.send_image` timeline management to branch logic, using `is_chunk_mode` to calculate progress differently for text chunks versus video frames
This commit replaces the raw regex text-splitting logic in `AutoLoopCalculatorTTS` with an "intelligent buffer" approach. It first splits the text by sentence terminators as before, but now aggregates these smaller segments until they contain a minimum of 5 words.
This prevents TTS models from generating robotic, out-of-context micro-audios when encountering trailing ellipses (`...`) or extremely short phrases, leading to more natural intonation and pacing.
All existing loop and timeline injections are preserved.
Replaced simple paragraph/sentence splitting with advanced regex
to gracefully handle split scenarios involving `.`, `?`, `!`,
quotes, ellipses, and `\n`. Punctuation is correctly retained on
the chunks to assure proper TTS intonation.
Moved `import re` to module level imports.
Refactors `IncrementalVideoStitcher.stitch` to eliminate in-place assignments
into a pre-allocated empty tensor when loading image frames in parallel, which
caused `RuntimeError: Inplace update to inference tensor outside InferenceMode
is not allowed.` in newer PyTorch versions.
The refactored implementation uses a pure map function to return individual
tensors and concatenates them sequentially using `torch.cat`, remaining thread-safe
and compatible with PyTorch's `InferenceMode`. Security against deserialization
vulnerabilities is preserved by ensuring `weights_only=True` remains when loading
audio caches.
Added `weights_only=True` to `torch.load()` in `video.py` to prevent insecure deserialization and potential arbitrary code execution via crafted pickle files. This change restricts the unpickler to only load tensors, primitive types, and basic containers, which is sufficient for the audio dictionary being loaded.
This commit introduces a new dropdown to the `AutoLoopCalculatorTTS` node inside `video.py`, allowing text to be split by either "Párrafos (Saltos de línea)" or "Frases (Puntos)". When splitting by sentences, it cleanly preserves the periods to maintain proper intonation in TTS systems. Output pins are renamed (`current_text`, `total_chunks`) for better semantics.
Introduced concurrent image loading and processing in the Video Stitcher node
using ThreadPoolExecutor. This optimizes the transition from disk-cached PNGs
to the final video tensor by parallelizing I/O and color conversion.
- Replaced sequential loop with ThreadPoolExecutor.map
- Wrapped executor.map in list() to ensure exception propagation
- Verified ~85% speedup in mocked I/O-bound benchmarks
- Registered `AutoLoopCalculatorTTS` in `NODE_DISPLAY_NAME_MAPPINGS`.
- Added `AutoLoopCalculatorTTS` class to `video.py` to allow looping through text paragraphs instead of video frames.
- Replaced the implementation of `IncrementalVideoStitcher` to cache audio tensors as `.pt` files and concatenate them along the time axis on the final cycle.
- Introduced `standardize_video_file` helper in `video.py`.
- The helper creates a physical video clone via FFmpeg, copying the video stream exactly to retain quality while limiting the audio stream.
- Audio limits are conditionally applied using `torchaudio.info` (<=44100Hz and <=2 Channels) to avoid unnecessary processing.
- Implemented a "Fail-Fast" approach with `raise Exception` if the FFmpeg cloning process fails, preventing silent downstream crashes.
- Injected the helper directly into `VideoAnalyzerFaceDetector` and `VideoAnalyzerSceneDetector` to secure the path passed down to VHS.
- Created `extract_and_standardize_audio` helper in `video.py` to standardize audio to 44100Hz and Stereo format.
- Refactored `VideoAnalyzerFaceDetector` and `VideoAnalyzerSceneDetector` to use the new helper function.
- Permanently deleted `modify_facedetector.py`, `modify_facedetector2.py`, and `modify_facedetector3.py` residual scripts.
- Renamed `VideoAnalyzerWithAudio` to `VideoAnalyzerFaceDetector`.
- Introduced `VIDEO_ANALYSIS_CACHE` and `current_loop_index` for cycle caching.
- Created `VideoAnalyzerSceneDetector` to detect scene changes via pixel difference.
- Added dynamic reference frame preview functionality outside the caching logic.
- Registered nodes with proper display names in `__init__.py`.
This commit addresses two primary requests:
1. Replaces all console log prefixes `[DEBUG]` (and variations) with `[Secuencial Batcher]`.
2. Extends the `RETURN_TYPES` and `RETURN_NAMES` of all nodes to output a `log` string containing exactly the text emitted via `print()`. This string is constructed by intercepting `print()` calls inside node methods using a local wrapper and appending the texts to a list, which is then returned joined by newlines.
Replaces the previous "multiple of 4" rule with the `4n + 1` logic across
the AutoLoopCalculatorWan and VAESafeFramePadder nodes. This prevents frame
loss / truncation inside the VAE and ensures absolute consistency for
long generation runs and video reconstruction. Mention of "múltiplo de 4"
in the primary README has also been updated to "regla de 4n + 1".
- Se introduce la subcarpeta `meisoft_video_cache`.
- Se guardan los lotes con un timestamp en milisegundos para evitar sobreescrituras en caso de que falle el `current_loop_index`.
- Se incorpora `@classmethod def IS_CHANGED` con `time.time()` para obligar a ComfyUI a ejecutar siempre el nodo e ignorar el cache.
- El directorio temporal se limpia correctamente en el ciclo 0 y se destruye tras ensamblar el vídeo completo.
Replaced artificial safe limit in AutoLoopCalculatorWan (video.py) and
AutoLoopCalculatorLTX (loop.py) with actual physical source frame limit.
This prevents trigger nodes from falsely requesting frames past the EOF
which resulted in "RuntimeError: No frames generated".
- Added VAESafeFramePadder to `tools.py` which clones the last frame
of an image tensor to satisfy mathematical rules (4n for WanVideo,
8n+1 for LTX) avoiding audio clipping and VAE crashes.
- Registered the new tool in `__init__.py` under NODE_DISPLAY_NAME_MAPPINGS.
- Updated `AutoLoopCalculatorWan` in `video.py` to pad and round up to a
multiple of 4.
- Updated `AutoLoopCalculatorLTX` in `loop.py` to pad and round up to an
8n+1 multiple.
Inject `comfy.utils.ProgressBar` into the frame scanning loop in `VideoAnalyzerWithAudio`. This provides a visual native green progress bar directly on the node in the ComfyUI interface, giving real-time feedback during long video analyses without requiring the user to monitor the terminal output.
Update `IS_CHANGED` in `VideoAnalyzerWithAudio` to rely on the video path
and node parameters instead of `os.path.getmtime` and `time.time()`. This fixes
an issue where the node would constantly invalidate the cache and re-run on
every execution, rather than reusing cached results when inputs have not changed.
This commit patches the `SessionImageSender`, `AutoLoopCalculatorWan`,
and `AutoLoopCalculatorLTX` nodes to prevent infinite loops caused by
extreme truncation at the end of video sequences.
- `image.py`: Ensures `SessionImageSender` accepts the entire batch if no
faces are detected, rather than defaulting to frame 0, which previously
trapped the workflow in a 1-frame micro-cycle loop.
- `video.py`: Updates `AutoLoopCalculatorWan` to always round the final
chunk size up to the nearest multiple of 4, removing the strict
cropping logic that broke the 3D VAE rule.
- `loop.py`: Updates `AutoLoopCalculatorLTX` to always round the final
chunk size up to the nearest `8n + 1` value, removing the strict
cropping logic that broke the DiT rule.
- Enforced a strict memory cleanup sequence in `MeisoftVRAMDefragmenter` (including IPC cleanup and CUDA synchronization).
- Injected `PYTORCH_CUDA_ALLOC_CONF="max_split_size_mb:128"` in `__init__.py` to prevent VRAM micro-fragmentation.
- Added `unload_detector` option to `VideoAnalyzerWithAudio` to eagerly destroy the face detector model and free VRAM.
- Created `MeisoftVRAMDefragmenter` in `vram_node.py` as a passthrough to force model unloading, Python garbage collection, and CUDA cache defragmentation.
- Registered the new node in `__init__.py`.
- Added light memory cleanup on intermediate batch loops in `loop.py`, alongside a heavy cleanup (including ctypes `malloc_trim`) at the end.
- Added `unload_detector_after_analysis` boolean flag to `VideoAnalyzerWithAudio` in `video.py` to allow releasing the BBOX detector model immediately after use.
- Updated `SessionImageSender` to conditionally save keyframe only when not in the final cycle.
- Updated `IncrementalVideoStitcher` to return full concatenated tensor when in the final cycle, avoiding dummy frame output and blocking downstream nodes.
- Expose `IS_FINAL_CYCLE` boolean from `IncrementalVideoStitcher` to UI for downstream conditionals.
- Fixed tuple index extraction (`res[0]`) for `SEGS` object in bbox_detector.
- Silenced Ultralytics/YOLO console spam by wrapping detection logic in `redirect_stdout`.
- Upgraded the `while True:` loop to a `for` loop with `tqdm` for a clean progress bar, while preserving the RGB frame conversion logic for accuracy.
- Patches `AutoLoopCalculator` in `video.py` to add base proportional adjustment without VAE constraints.
- Patches `AutoLoopCalculatorLTX` in `loop.py` to enforce the strict 8n + 1 frame rule for LTX models, matching its calculation mathematically correctly for proportional chunking.
- Fixes `__pycache__` to be excluded correctly.
- Add optional `bbox_detector` input to `VideoAnalyzerWithAudio`.
- Implement GPU-accelerated face detection using external BBOX_DETECTOR models.
- Support both ImpactPack and standard ONNX bounding box output formats.
- Retain CPU-based OpenCV face detection as a fallback.
- Rename node in UI to "🕵️ Video Analyzer Face detector + Audio".
- Update README.md and README_EN.md to reflect new architecture and wiring.
Changed the output type for the video path in the VideoAnalyzerWithAudio
node from STRING to `*` to allow for flexible wildcard connections in
ComfyUI. Also updated the return name to video_path to accurately
reflect the output variable.
- Improve error handling in video.py to capture and display Torchaudio exceptions.
- Add explicit list of dependencies in requirements.txt.
- Introduce install.py for automated installation of Python and OS dependencies (FFmpeg).
- Complete redesign of Spanish and English READMEs with v1.5.2 Changelog, new features, and professional workflow setup.
Updated the `VideoAnalyzerWithAudio` node in `video.py` to match the exact behavior of `VHS_LoadVideo`. By removing the wildcard (`*`) hack and providing a valid tuple with a local file list alongside `{"forceInput": False, "video_upload": True}`, the node now officially renders a standard ComfyUI file uploader widget that can be cleanly converted to a `STRING` input via right-click ("Convert video to input").
Also retained the absolute `VALIDATE_INPUTS` shield returning `True`, guaranteeing dynamic wire inputs (e.g. from YTDLP) won't cause ComfyUI execution queue validation errors when dealing with paths generated at runtime. Cleaned up internal list unpacking hacks in `IS_CHANGED` and `analyze` since standard strings are now properly passed.
Replaced the strict 'STRING' input type with the '*' wildcard in `VideoAnalyzerWithAudio`. This bypasses ComfyUI's strict type checking for the input port, allowing downloading nodes (like YTDPL) that output custom types (e.g., `VIDEO_PATH` or `PATH`) to connect seamlessly. Updated `VALIDATE_INPUTS` comments to reflect its role as a 'Total Shield' for bypassing dynamic path validation.
Deleted `opt_video_path` parameter and the strict `VALIDATE_INPUTS` classmethod in `VideoAnalyzerWithAudio`. ComfyUI was validating the cached manual widget value before downstream dynamic nodes could finish processing strings. Routing everything directly through a single `video` input and completely removing `VALIDATE_INPUTS` properly delegates execution dependency to ComfyUI's native graph path order.
Implemented a hybrid validation logic in the `VALIDATE_INPUTS` method of `VideoAnalyzerWithAudio`.
This bypasses the strict `os.path.exists()` check if the optional dynamic input (`opt_video_path`) is connected, allowing ComfyUI to start the workflow and wait for upstream nodes (like downloaders) to create the file at runtime.
Strict physical file validation is maintained for the standard manual video upload widget.
Added an optional `opt_video_path` string input (with `forceInput: True`) to the `VideoAnalyzerWithAudio` node. This allows the node to receive a video path from another upstream node physically via a wire connection, bypassing the default file upload widget when connected. The `IS_CHANGED`, `VALIDATE_INPUTS` and `analyze` methods were uniformly updated to intercept and prioritize this new optional input.
Update `VideoAnalyzerWithAudio` in `video.py` to support absolute paths for the `video_name` parameter. The node's `IS_CHANGED`, `VALIDATE_INPUTS`, and `analyze` methods have been modified to first check if the provided path exists directly using `os.path.exists()`. If it does, it uses the path directly, enabling the use of absolute paths. Otherwise, it falls back to the default `folder_paths.get_annotated_filepath()`.
- Register `AutoLoopCalculatorWan` with its visual display name in `__init__.py`.
- Append `AutoLoopCalculatorWan` class definition to `video.py`.
- The new node enforces strict truncation in multiples of 4 to prevent 3D VAE crashes on the WanVideo model while skipping asymmetric trailing frames.