From b452bd8eda63045df6ce593aa8e97af886b72916 Mon Sep 17 00:00:00 2001 From: dongxiaoman Date: Tue, 5 May 2026 14:26:48 -0700 Subject: [PATCH] add audo detection node --- __init__.py | 5 +-- video_has_audio_node.py | 77 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 video_has_audio_node.py diff --git a/__init__.py b/__init__.py index dd5082d..362e2a6 100644 --- a/__init__.py +++ b/__init__.py @@ -1,7 +1,8 @@ from .predefined_resolution_node import NODE_CLASS_MAPPINGS as RESOLUTION_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as RESOLUTION_DISPLAY_MAPPINGS from .none_constant_node import NODE_CLASS_MAPPINGS as NONE_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as NONE_DISPLAY_MAPPINGS +from .video_has_audio_node import NODE_CLASS_MAPPINGS as VIDEO_AUDIO_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS as VIDEO_AUDIO_DISPLAY_MAPPINGS -NODE_CLASS_MAPPINGS = {**RESOLUTION_MAPPINGS, **NONE_MAPPINGS} -NODE_DISPLAY_NAME_MAPPINGS = {**RESOLUTION_DISPLAY_MAPPINGS, **NONE_DISPLAY_MAPPINGS} +NODE_CLASS_MAPPINGS = {**RESOLUTION_MAPPINGS, **NONE_MAPPINGS, **VIDEO_AUDIO_MAPPINGS} +NODE_DISPLAY_NAME_MAPPINGS = {**RESOLUTION_DISPLAY_MAPPINGS, **NONE_DISPLAY_MAPPINGS, **VIDEO_AUDIO_DISPLAY_MAPPINGS} __all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS'] diff --git a/video_has_audio_node.py b/video_has_audio_node.py new file mode 100644 index 0000000..18cd194 --- /dev/null +++ b/video_has_audio_node.py @@ -0,0 +1,77 @@ +import subprocess +import json +import shutil + + +class VideoHasAudioNode: + @classmethod + def INPUT_TYPES(cls): + return { + "required": { + "input_file": ("STRING", { + "default": "", + "multiline": False, + "forceInput": False + }), + } + } + + RETURN_TYPES = ("BOOLEAN", "INT") + RETURN_NAMES = ("has_audio", "int_value") + FUNCTION = "detect_audio" + CATEGORY = "utils" + + @classmethod + def IS_CHANGED(cls, input_file): + return input_file + + def detect_audio(self, input_file): + has_audio = self._probe_has_audio(input_file) + return (has_audio, 1 if has_audio else 0) + + def _probe_has_audio(self, input_file): + if not input_file or not input_file.strip(): + return False + + ffprobe = shutil.which("ffprobe") or "ffprobe" + cmd = [ + ffprobe, + "-v", "error", + "-select_streams", "a", + "-show_entries", "stream=index", + "-of", "json", + input_file, + ] + + try: + result = subprocess.run( + cmd, + capture_output=True, + text=True, + check=True, + ) + except FileNotFoundError: + raise RuntimeError( + "ffprobe not found. Please install ffmpeg and ensure ffprobe is on PATH." + ) + except subprocess.CalledProcessError as e: + raise RuntimeError( + f"ffprobe failed for '{input_file}': {e.stderr.strip()}" + ) + + try: + data = json.loads(result.stdout or "{}") + except json.JSONDecodeError: + return False + + streams = data.get("streams") or [] + return len(streams) > 0 + + +NODE_CLASS_MAPPINGS = { + "VideoHasAudio": VideoHasAudioNode +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "VideoHasAudio": "Video Has Audio" +}