Blender 5.0 compat + STB XML import + sequence/stamps improvements

- Fix Blender 5.0 API: active_sequence_strip → active_strip, bracket
  property access on AddonPreferences, _RestrictContext during register()
- Fix new_effect() frame_end → length for Blender 5.0
- Fix OTIO adapter kwargs (rate/ignore_timecode_mismatch only for cmx_3600)
- Fix OTIO global_start_time RationalTime → int conversion
- Add Import STB XML operator with movie strip import and XML patching
  for Storyboard Pro transitions missing <alignment>
- Add Create Sequence Strip operator (select shots → create sequence)
- Improve Set Stamps: channel at top, no conflict with existing strips,
  use raw strip names in templates
- TVSHOW episode fixes: sequence loading, episode creation
- Kitsu: new_asset, new_episode, admin_connect fix, gazu version pin
- Fix escape warnings in file_utils regex patterns
- Guard handler registration against duplicates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-10 16:09:03 +01:00
co-authored by Claude Opus 4.6
parent c46d78f2ae
commit d2d64dc8a8
14 changed files with 548 additions and 122 deletions
+11 -7
View File
@@ -139,7 +139,7 @@ class VSETB_PT_strip(Panel):
@classmethod
def poll(cls, context):
strip = context.active_sequence_strip
strip = context.active_strip
return strip and get_channel_name(strip) == 'Shots'
def draw(self, context):
@@ -174,7 +174,7 @@ class VSETB_PT_sequencer(VSETB_main, Panel):
settings = get_scene_settings()
project = settings.active_project
strip = context.active_sequence_strip
strip = context.active_strip
channel = get_channel_name(strip)
col = layout.column()
@@ -224,6 +224,7 @@ class VSETB_PT_imports(VSETB_main, Panel):
#col.operator('vse_toolbox.import_files', text='Import', icon='IMPORT')
col.operator('vse_toolbox.import_spreadsheet', text='Import Spreadsheet', icon='SPREADSHEET')
col.operator("vse_toolbox.import_shots", text='Import Shots', icon="FILE_MOVIE")
col.operator("vse_toolbox.import_stb_xml", text='Import STB XML', icon="FILE_TEXT")
class VSETB_PT_presets(PresetPanel, Panel):
@@ -264,10 +265,10 @@ class VSETB_PT_tracker(VSETB_main, Panel):
@classmethod
def poll(cls, context):
return context.active_sequence_strip
return context.active_strip
def draw_header_preset(self, context):
active_strip = context.active_sequence_strip
active_strip = context.active_strip
self.layout.label(text=active_strip.name)
def draw(self, context):
@@ -280,7 +281,7 @@ class VSETB_PT_casting(VSETB_main, Panel):
@classmethod
def poll(cls, context):
strip = context.active_sequence_strip
strip = context.active_strip
return strip and get_channel_name(strip) == 'Shots'
def draw(self, context):
@@ -315,6 +316,8 @@ class VSETB_PT_casting(VSETB_main, Panel):
col_tool.separator()
col_tool.operator('vse_toolbox.casting_replace', icon='ZOOM_ALL', text="")
col_tool.separator()
col_tool.operator('vse_toolbox.casting_create_asset', icon='PLUS', text="")
if strip_settings.casting:
casting_item = strip_settings.casting[strip_settings.casting_index]
@@ -336,7 +339,7 @@ class VSETB_PT_metadata(VSETB_main, Panel):
@classmethod
def poll(cls, context):
return context.active_sequence_strip and get_scene_settings().active_project
return context.active_strip and get_scene_settings().active_project
def draw(self, context):
@@ -383,7 +386,7 @@ class VSETB_PT_comments(VSETB_main, Panel):
@classmethod
def poll(cls, context):
return context.active_sequence_strip and get_scene_settings().active_project
return context.active_strip and get_scene_settings().active_project
def draw(self, context):
layout = self.layout
@@ -455,6 +458,7 @@ class VSETB_MT_main_menu(Menu):
layout.operator('vse_toolbox.remove_channel', text='Remove Channel', icon='TRIA_DOWN_BAR')
layout.separator()
layout.operator('vse_toolbox.merge_shot_strips', text='Merge Shots')
layout.operator('vse_toolbox.create_sequence_strip', text='Create Sequence')
layout.operator('vse_toolbox.scene_cut_detection', text='Scene Cut Detection', icon='SCULPTMODE_HLT')
def draw_vse_toolbox_menu(self, context):
+6 -2
View File
@@ -91,7 +91,11 @@ def load_prefs():
continue
setattr(tracker_pref, k, os.path.expandvars(v))
prefs['tracker_name'] = prefs_datas['tracker_name']
try:
settings = get_scene_settings()
settings.tracker_name = prefs_datas['tracker_name']
except AttributeError:
pass # Scene not available yet during register()
class Trackers(PropertyGroup):
@@ -155,7 +159,7 @@ def register():
config_path = os.getenv('VSE_TOOLBOX_CONFIG')
if config_path:
prefs['config_path'] = os.path.expandvars(config_path)
prefs.config_path = os.path.expandvars(config_path)
load_prefs()
+25 -4
View File
@@ -299,7 +299,28 @@ def get_episodes_items(self, context):
def on_episode_updated(self, context):
settings = get_scene_settings()
os.environ['TRACKER_EPISODE_ID'] = settings.active_episode.id
project = settings.active_project
episode = settings.active_episode
if not episode or not episode.id:
return
os.environ['TRACKER_EPISODE_ID'] = episode.id
# Reload sequences for the selected episode (TVSHOW workflow)
prefs = get_addon_prefs()
tracker = prefs.tracker
if not tracker or not project:
return
project.sequences.clear()
try:
for seq in tracker.get_sequences(project.id, episode=episode.id):
item = project.sequences.add()
item.name = seq['name']
item.id = seq['id']
except Exception as e:
print(f'Could not load sequences for episode {episode.name}: {e}')
class Project(PropertyGroup):
id : StringProperty(default='')
@@ -715,7 +736,7 @@ class VSETB_PGT_strip_settings(PropertyGroup):
@property
def strip(self):
sequences = bpy.context.scene.sequence_editor.sequences_all
sequences = bpy.context.scene.sequence_editor.strips_all
return next(s for s in sequences if s.vsetb_strip_settings == self)
@property
@@ -808,7 +829,7 @@ def register():
bpy.utils.register_class(cls)
bpy.types.Scene.vsetb_settings = PointerProperty(type=VSETB_PGT_scene_settings)
bpy.types.Sequence.vsetb_strip_settings = PointerProperty(type=VSETB_PGT_strip_settings)
bpy.types.Strip.vsetb_strip_settings = PointerProperty(type=VSETB_PGT_strip_settings)
#load_metadata_types()
bpy.app.handlers.load_post.append(load_handler)
@@ -818,7 +839,7 @@ def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)
del bpy.types.Sequence.vsetb_strip_settings
del bpy.types.Strip.vsetb_strip_settings
del bpy.types.Scene.vsetb_settings
bpy.app.handlers.load_post.remove(load_handler)