fix(control): prevent duplicate save_video and unmask video module shadow

When a video script (animatediff, text2video, image2video, stablevideodiffusion)
runs via Control tab, both the script's save and control_run's end-of-run save
fired. The latter crashed silently because the local `video` cv2 capture name at
control_run:584 shadowed the modules.video import, so the duplicate was hidden
and the gallery video link never propagated.

- alias import as video_module to bypass the shadow
- p.video_saved marker set by each script
- control_run skips its end-of-run save when the marker is set
This commit is contained in:
CalamitousFelicitousness
2026-04-27 01:32:30 +01:00
parent b48bf5236b
commit ba4436916d
5 changed files with 7 additions and 2 deletions
+3 -2
View File
@@ -19,6 +19,7 @@ from modules.ui_common import infotext_to_html
from modules.api import script
from modules.generation_parameters_copypaste import create_override_settings_dict
from modules.paths import resolve_output_path
from modules import video as video_module # alias avoids shadow by local `video` cv2 capture name at control_run:584
debug = os.environ.get('SD_CONTROL_DEBUG', None) is not None
@@ -795,9 +796,9 @@ def control_run(state: str = '', # pylint: disable=keyword-arg-before-vararg
image_txt = ''
p.init_images = output_images # may be used for hires
if video_type != 'None' and isinstance(output_images, list) and 'video' in p.ops:
if video_type != 'None' and isinstance(output_images, list) and 'video' in p.ops and not getattr(p, 'video_saved', False):
p.do_not_save_grid = True # pylint: disable=attribute-defined-outside-init
output_filename = video.save_video(p, filename=None, images=output_images, video_type=video_type, duration=video_duration, loop=video_loop, pad=video_pad, interpolate=video_interpolate, sync=True)
output_filename = video_module.save_video(p, filename=None, images=output_images, video_type=video_type, duration=video_duration, loop=video_loop, pad=video_pad, interpolate=video_interpolate, sync=True)
if shared.opts.gradio_skip_video:
output_filename = ''
image_txt = f'| Frames {len(output_images)} | Size {output_images[0].width}x{output_images[0].height}'
+1
View File
@@ -268,3 +268,4 @@ class AnimateDiffScript(scripts_manager.Script):
if video_type != 'None':
log.debug(f'AnimateDiff video: type={video_type} duration={duration} loop={gif_loop} pad={mp4_pad} interpolate={mp4_interpolate}')
save_video(p, filename=None, images=processed.images, video_type=video_type, duration=duration, loop=gif_loop, pad=mp4_pad, interpolate=mp4_interpolate)
p.video_saved = True
+1
View File
@@ -112,4 +112,5 @@ class VGenI2VScript(scripts_manager.Script):
shared.sd_model = orig_pipeline
if video_type != 'None' and processed is not None:
video.save_video(p, filename=None, images=processed.images, video_type=video_type, duration=duration, loop=gif_loop, pad=mp4_pad, interpolate=mp4_interpolate)
p.video_saved = True
return processed
+1
View File
@@ -123,4 +123,5 @@ class SVDScript(scripts_manager.Script):
processed = processing.process_images(p)
if video_type != 'None':
video.save_video(p, filename=None, images=processed.images, video_type=video_type, duration=duration, loop=gif_loop, pad=mp4_pad, interpolate=mp4_interpolate)
p.video_saved = True
return processed
+1
View File
@@ -91,4 +91,5 @@ class ModelScopeScript(scripts_manager.Script):
if video_type != 'None':
video.save_video(p, filename=None, images=processed.images, video_type=video_type, duration=duration, loop=gif_loop, pad=mp4_pad, interpolate=mp4_interpolate)
p.video_saved = True
return processed