@@ -975,16 +975,30 @@ def _skill_to_filters(
975975 # If skill has a template, use it
976976 if skill .ffmpeg_template :
977977 template = skill .ffmpeg_template
978- for key , value in params .items ():
979- val_str = str (value )
980- if isinstance (value , str ):
981- val_str = sanitize_text_param (val_str )
982- template = template .replace (f"{{{ key } }}" , val_str )
983978
984- # Resolve any remaining {placeholder} with skill defaults
985- for sp in (skill .parameters or []):
986- if sp .default is not None :
987- template = template .replace (f"{{{ sp .name } }}" , str (sp .default ))
979+ # Optimization: Skip replacements entirely if there are no placeholders
980+ if "{" in template :
981+ for key , value in params .items ():
982+ val_str = str (value )
983+ if isinstance (value , str ):
984+ val_str = sanitize_text_param (val_str )
985+
986+ # Unconditional replace is fast here because user params are few
987+ # and likely present in the template.
988+ template = template .replace (f"{{{ key } }}" , val_str )
989+
990+ # Resolve any remaining {placeholder} with skill defaults
991+ if "{" in template :
992+ for sp in (skill .parameters or []):
993+ if sp .default is not None :
994+ # Optimization: "Check First" pattern. Skills often have
995+ # many default parameters that aren't in the template.
996+ placeholder = f"{{{ sp .name } }}"
997+ if placeholder in template :
998+ template = template .replace (placeholder , str (sp .default ))
999+ # Optimization: Early break if all placeholders are resolved
1000+ if "{" not in template :
1001+ break
9881002
9891003 # Determine if it's a video filter, audio filter, or output option
9901004 if template .startswith ("-" ):
@@ -1005,14 +1019,23 @@ def _skill_to_filters(
10051019 _defaults [sp .name ] = str (sp .default )
10061020
10071021 for step_str in skill .pipeline :
1008- # Substitute {placeholder} values from parent params
1009- for key , value in params .items ():
1010- step_str = step_str .replace (f"{{{ key } }}" , str (value ))
1011-
1012- # Resolve any remaining {placeholder} with skill defaults
1013- # to prevent literal "{ratio}" from reaching handlers.
1014- for key , default_val in _defaults .items ():
1015- step_str = step_str .replace (f"{{{ key } }}" , default_val )
1022+ # Optimization: Skip replacements entirely if there are no placeholders
1023+ if "{" in step_str :
1024+ # Substitute {placeholder} values from parent params
1025+ for key , value in params .items ():
1026+ step_str = step_str .replace (f"{{{ key } }}" , str (value ))
1027+
1028+ # Resolve any remaining {placeholder} with skill defaults
1029+ # to prevent literal "{ratio}" from reaching handlers.
1030+ if "{" in step_str :
1031+ for key , default_val in _defaults .items ():
1032+ # Optimization: "Check First" pattern
1033+ placeholder = f"{{{ key } }}"
1034+ if placeholder in step_str :
1035+ step_str = step_str .replace (placeholder , default_val )
1036+ # Optimization: Early break if all placeholders are resolved
1037+ if "{" not in step_str :
1038+ break
10161039
10171040 # Parse step string (format: "skill_name:param1=val1,param2=val2")
10181041 if ":" in step_str :
0 commit comments