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
+75 -12
View File
@@ -53,7 +53,7 @@ class VSETB_OT_casting_replace(Operator):
item = self.assets.add()
item.name = asset.tracker_name
strip = context.active_sequence_strip
strip = context.active_strip
asset_casting_index = strip.vsetb_strip_settings.casting_index
active_asset = strip.vsetb_strip_settings.casting[asset_casting_index].asset
@@ -87,7 +87,7 @@ class VSETB_OT_casting_add(Operator):
#asset_name : EnumProperty(name='', items=get_scene_settings().active_project.get('asset_items', []))
@classmethod
def poll(cls, context):
active_strip = context.active_sequence_strip
active_strip = context.active_strip
if active_strip:
return True
@@ -135,7 +135,7 @@ class VSETB_OT_casting_remove(Operator):
@classmethod
def poll(cls, context):
active_strip = context.active_sequence_strip
active_strip = context.active_strip
if active_strip:
return True
@@ -190,7 +190,7 @@ class VSETB_OT_casting_move(Operator):
@classmethod
def poll(cls, context):
active_strip = context.active_sequence_strip
active_strip = context.active_strip
if active_strip:
return True
@@ -231,7 +231,7 @@ class VSETB_OT_copy_casting(Operator):
def poll(cls, context):
if not context.scene.sequence_editor:
return
active_strip = context.active_sequence_strip
active_strip = context.active_strip
strip_settings = get_strip_settings()
if active_strip and strip_settings.casting:
@@ -256,7 +256,7 @@ class VSETB_OT_paste_casting(Operator):
@classmethod
def poll(cls, context):
return context.active_sequence_strip
return context.active_strip
def invoke(self, context, event):
self.mode = 'REPLACE'
@@ -279,7 +279,7 @@ class VSETB_OT_paste_casting(Operator):
casting_datas = json.loads(CASTING_BUFFER.read_text())
casting_ids = set(c['id'] for c in casting_datas)
for strip in context.selected_sequences:
for strip in context.selected_strips:
strip_settings = strip.vsetb_strip_settings
if self.mode == 'REPLACE':
@@ -317,7 +317,7 @@ class VSETB_OT_copy_metadata(Operator):
@classmethod
def poll(cls, context):
return context.selected_sequences and context.active_sequence_strip
return context.selected_strips and context.active_strip
def execute(self, context):
prefs = get_addon_prefs()
@@ -329,11 +329,11 @@ class VSETB_OT_copy_metadata(Operator):
if not metadata:
self.report({'ERROR'}, f'No Metadata named {self.metadata}')
active_strip = context.active_sequence_strip
active_strip = context.active_strip
metadata_value = getattr(active_strip.vsetb_strip_settings.metadata, metadata)
for strip in context.selected_sequences:
if strip == context.active_sequence_strip:
for strip in context.selected_strips:
if strip == context.active_strip:
continue
setattr(strip.vsetb_strip_settings.metadata, metadata, metadata_value)
@@ -341,6 +341,68 @@ class VSETB_OT_copy_metadata(Operator):
return {"FINISHED"}
def get_asset_type_items(self, context):
settings = get_scene_settings()
project = settings.active_project
if project and project.asset_types:
return [(t.name, t.name, '') for t in project.asset_types]
return [('Character', 'Character', '')]
class VSETB_OT_casting_create_asset(Operator):
bl_idname = "vse_toolbox.casting_create_asset"
bl_label = "Create & Cast Asset"
bl_description = "Create a new asset in Kitsu and add to casting"
bl_options = {"REGISTER", "UNDO"}
asset_name: StringProperty(name="Name")
asset_type: EnumProperty(name="Type", items=get_asset_type_items)
description: StringProperty(name="Description")
@classmethod
def poll(cls, context):
settings = get_scene_settings()
return settings.active_project
def invoke(self, context, event):
return context.window_manager.invoke_props_dialog(self)
def execute(self, context):
prefs = get_addon_prefs()
settings = get_scene_settings()
project = settings.active_project
tracker = prefs.tracker
try:
new_asset_data = tracker.new_asset(
self.asset_name, self.asset_type,
project=project.id, description=self.description
)
except Exception as e:
self.report({'ERROR'}, str(e))
return {'CANCELLED'}
# Add to local project assets
asset = project.assets.add()
asset.name = new_asset_data['id']
asset.id = new_asset_data['id']
asset.tracker_name = new_asset_data['name']
asset.asset_type = self.asset_type
# Cast to selected shot strips
strips = get_strips('Shots', selected_only=True)
for strip in strips:
strip_settings = strip.vsetb_strip_settings
cast_item = strip_settings.casting.add()
cast_item.name = new_asset_data['id']
cast_item.id = new_asset_data['id']
cast_item['_name'] = self.asset_name
strip_settings.casting.update()
self.report({'INFO'}, f"Created asset '{self.asset_name}' and cast to {len(strips)} shots")
return {'FINISHED'}
classes = (
VSETB_OT_casting_add,
VSETB_OT_casting_remove,
@@ -348,7 +410,8 @@ classes = (
VSETB_OT_copy_casting,
VSETB_OT_paste_casting,
VSETB_OT_casting_replace,
VSETB_OT_copy_metadata
VSETB_OT_copy_metadata,
VSETB_OT_casting_create_asset,
)
def register():