feat(video): add path-string loader variant
UniverSR Load Video Audio (Path) mirrors FoleyTuneVideoLoader: takes an absolute video_path (for files outside input/) and outputs the same (UNIVERSR_VIDEO, AUDIO). Shared load body factored into _load_video_audio; registered for the inline preview (post-run) in the web extension. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -162,6 +162,9 @@ button and drag-and-drop, just like a normal video loader. Outputs **`UNIVERSR_V
|
|||||||
| `start_time` *(opt.)* | float | `0.0` | Trim start, seconds. |
|
| `start_time` *(opt.)* | float | `0.0` | Trim start, seconds. |
|
||||||
| `duration` *(opt.)* | float | `0.0` | Trim length, seconds (`0` = to end). |
|
| `duration` *(opt.)* | float | `0.0` | Trim length, seconds (`0` = to end). |
|
||||||
|
|
||||||
|
There is also a **UniverSR Load Video Audio (Path)** variant that takes an absolute `video_path` string
|
||||||
|
(for files outside ComfyUI's `input/` folder); it previews after you run it. Both feed the combiner.
|
||||||
|
|
||||||
### UniverSR Video Combiner
|
### UniverSR Video Combiner
|
||||||
|
|
||||||
Muxes an `AUDIO` track onto the source video **without re-encoding the video** (`-c:v copy`) and saves
|
Muxes an `AUDIO` track onto the source video **without re-encoding the video** (`-c:v copy`) and saves
|
||||||
|
|||||||
+63
-17
@@ -120,6 +120,27 @@ def _list_input_videos() -> list:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
def _load_video_audio(video_path: str, start_time: float, duration: float) -> dict:
|
||||||
|
"""Shared loader body: extract audio + build the (video, audio) result and preview."""
|
||||||
|
if not video_path or not os.path.isfile(video_path):
|
||||||
|
raise FileNotFoundError(f"Video not found: {video_path}")
|
||||||
|
|
||||||
|
waveform, sr = _extract_audio(video_path, start_time, duration)
|
||||||
|
dur = waveform.shape[-1] / max(sr, 1)
|
||||||
|
print(f"[UniverSR] Loaded audio from {os.path.basename(video_path)}: "
|
||||||
|
f"{waveform.shape[1]}ch @ {sr} Hz ({dur:.2f}s)")
|
||||||
|
|
||||||
|
audio = {"waveform": waveform, "sample_rate": sr}
|
||||||
|
info = {"video_path": os.path.abspath(video_path), "start_time": float(start_time),
|
||||||
|
"duration": float(duration), "source_sr": sr, "source_channels": int(waveform.shape[1])}
|
||||||
|
|
||||||
|
temp_name = _temp_preview_symlink(video_path)
|
||||||
|
ext = (os.path.splitext(video_path)[1] or ".mp4").lstrip(".")
|
||||||
|
return {"ui": {"gifs": [{"filename": temp_name, "subfolder": "", "type": "temp",
|
||||||
|
"format": f"video/{ext}"}]},
|
||||||
|
"result": (info, audio)}
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Load Video Audio (mirrors FoleyTuneVideoLoaderUpload; outputs video + audio)
|
# Load Video Audio (mirrors FoleyTuneVideoLoaderUpload; outputs video + audio)
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
@@ -154,23 +175,7 @@ class UniverSRLoadVideoAudio:
|
|||||||
|
|
||||||
def load(self, video, start_time=0.0, duration=0.0):
|
def load(self, video, start_time=0.0, duration=0.0):
|
||||||
video_path = folder_paths.get_annotated_filepath(video)
|
video_path = folder_paths.get_annotated_filepath(video)
|
||||||
if not video_path or not os.path.isfile(video_path):
|
return _load_video_audio(video_path, start_time, duration)
|
||||||
raise FileNotFoundError(f"Video not found: {video}")
|
|
||||||
|
|
||||||
waveform, sr = _extract_audio(video_path, start_time, duration)
|
|
||||||
dur = waveform.shape[-1] / max(sr, 1)
|
|
||||||
print(f"[UniverSR] Loaded audio from {os.path.basename(video_path)}: "
|
|
||||||
f"{waveform.shape[1]}ch @ {sr} Hz ({dur:.2f}s)")
|
|
||||||
|
|
||||||
audio = {"waveform": waveform, "sample_rate": sr}
|
|
||||||
info = {"video_path": os.path.abspath(video_path), "start_time": float(start_time),
|
|
||||||
"duration": float(duration), "source_sr": sr, "source_channels": int(waveform.shape[1])}
|
|
||||||
|
|
||||||
temp_name = _temp_preview_symlink(video_path)
|
|
||||||
ext = (os.path.splitext(video_path)[1] or ".mp4").lstrip(".")
|
|
||||||
return {"ui": {"gifs": [{"filename": temp_name, "subfolder": "", "type": "temp",
|
|
||||||
"format": f"video/{ext}"}]},
|
|
||||||
"result": (info, audio)}
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def IS_CHANGED(cls, video, start_time=0.0, duration=0.0):
|
def IS_CHANGED(cls, video, start_time=0.0, duration=0.0):
|
||||||
@@ -188,6 +193,45 @@ class UniverSRLoadVideoAudio:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
# Load Video Audio (Path) (mirrors FoleyTuneVideoLoader; outputs video + audio)
|
||||||
|
# --------------------------------------------------------------------------- #
|
||||||
|
class UniverSRLoadVideoAudioPath:
|
||||||
|
"""Same as UniverSR Load Video Audio, but takes an absolute file path instead of
|
||||||
|
an upload — handy for files outside ComfyUI's input/ folder. Previews after running."""
|
||||||
|
|
||||||
|
DESCRIPTION = "Load a video by file path: outputs its audio (to super-resolve) and a reference (to remux)."
|
||||||
|
CATEGORY = "audio/UniverSR"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def INPUT_TYPES(cls):
|
||||||
|
return {
|
||||||
|
"required": {
|
||||||
|
"video_path": ("STRING", {"default": "", "placeholder": "/path/to/video.mp4"}),
|
||||||
|
},
|
||||||
|
"optional": {
|
||||||
|
"start_time": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 360000.0, "step": 0.1,
|
||||||
|
"tooltip": "Trim start in seconds."}),
|
||||||
|
"duration": ("FLOAT", {"default": 0.0, "min": 0.0, "max": 360000.0, "step": 0.1,
|
||||||
|
"tooltip": "Trim length in seconds (0 = to end)."}),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
RETURN_TYPES = ("UNIVERSR_VIDEO", "AUDIO")
|
||||||
|
RETURN_NAMES = ("video", "audio")
|
||||||
|
FUNCTION = "load"
|
||||||
|
OUTPUT_NODE = True
|
||||||
|
|
||||||
|
def load(self, video_path, start_time=0.0, duration=0.0):
|
||||||
|
return _load_video_audio((video_path or "").strip(), start_time, duration)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def IS_CHANGED(cls, video_path, start_time=0.0, duration=0.0):
|
||||||
|
p = (video_path or "").strip()
|
||||||
|
m = os.path.getmtime(p) if p and os.path.isfile(p) else 0
|
||||||
|
return f"{video_path}:{start_time}:{duration}:{m}"
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
# Video Combiner (mirrors FoleyTuneVideoCombiner)
|
# Video Combiner (mirrors FoleyTuneVideoCombiner)
|
||||||
# --------------------------------------------------------------------------- #
|
# --------------------------------------------------------------------------- #
|
||||||
@@ -281,9 +325,11 @@ class UniverSRVideoCombiner:
|
|||||||
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
NODE_CLASS_MAPPINGS = {
|
||||||
"UniverSRLoadVideoAudio": UniverSRLoadVideoAudio,
|
"UniverSRLoadVideoAudio": UniverSRLoadVideoAudio,
|
||||||
|
"UniverSRLoadVideoAudioPath": UniverSRLoadVideoAudioPath,
|
||||||
"UniverSRVideoCombiner": UniverSRVideoCombiner,
|
"UniverSRVideoCombiner": UniverSRVideoCombiner,
|
||||||
}
|
}
|
||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||||
"UniverSRLoadVideoAudio": "UniverSR Load Video Audio",
|
"UniverSRLoadVideoAudio": "UniverSR Load Video Audio",
|
||||||
|
"UniverSRLoadVideoAudioPath": "UniverSR Load Video Audio (Path)",
|
||||||
"UniverSRVideoCombiner": "UniverSR Video Combiner",
|
"UniverSRVideoCombiner": "UniverSR Video Combiner",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,6 +150,9 @@ app.registerExtension({
|
|||||||
addVideoPreview(nodeType);
|
addVideoPreview(nodeType);
|
||||||
addUploadWidget(nodeType);
|
addUploadWidget(nodeType);
|
||||||
}
|
}
|
||||||
|
if (nodeData?.name === "UniverSRLoadVideoAudioPath") {
|
||||||
|
addVideoPreview(nodeType);
|
||||||
|
}
|
||||||
if (nodeData?.name === "UniverSRVideoCombiner") {
|
if (nodeData?.name === "UniverSRVideoCombiner") {
|
||||||
addVideoPreview(nodeType);
|
addVideoPreview(nodeType);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user