import json import bpy from bpy.types import Context, Event, PropertyGroup, Operator from bpy.props import (CollectionProperty, EnumProperty, StringProperty) from vse_toolbox.constants import CASTING_BUFFER, ASSET_ITEMS from vse_toolbox.sequencer_utils import get_strips from vse_toolbox.bl_utils import (get_addon_prefs, get_scene_settings, get_strip_settings) from time import perf_counter class VSETB_OT_casting_replace(Operator): bl_idname = "vse_toolbox.casting_replace" bl_label = "Replace Asset" bl_description = "Replace Asset of selected strips" old_asset : StringProperty() new_asset : StringProperty() assets : CollectionProperty(type=PropertyGroup) def execute(self, context): prefs = get_addon_prefs() settings = get_scene_settings() new_asset = next(a for a in settings.active_project.assets if a.tracker_name == self.new_asset) for strip in get_strips('Shots', selected_only=True): strip_settings = strip.vsetb_strip_settings for asset_casting in strip_settings.casting: if asset_casting.asset.tracker_name == self.old_asset: print(f'Replace casting on {strip.name}') asset_casting.name = new_asset.name asset_casting.id = new_asset.id asset_casting['_name'] = new_asset.label strip_settings.casting.update() self.assets.clear() return {'FINISHED'} def invoke(self, context, event): settings = get_scene_settings() project = settings.active_project self.assets.clear() for asset in project.assets: item = self.assets.add() item.name = asset.tracker_name strip = context.active_sequence_strip asset_casting_index = strip.vsetb_strip_settings.casting_index active_asset = strip.vsetb_strip_settings.casting[asset_casting_index].asset self.old_asset = active_asset.tracker_name self.new_asset = '' return context.window_manager.invoke_props_dialog(self) # def draw(self, context): scn = context.scene settings = get_scene_settings() project = settings.active_project layout = self.layout col = layout.column() col.use_property_split = True col.prop_search(self, 'old_asset', self, 'assets', text='Old Asset', icon='ASSET_MANAGER') col.prop_search(self, 'new_asset', self, 'assets', text='New Asset', icon='ASSET_MANAGER') class VSETB_OT_casting_add(Operator): bl_idname = "vse_toolbox.casting_add" bl_label = "Casting Add" bl_description = "Add Asset to Castin" bl_options = {"REGISTER", "UNDO"} bl_property = "asset_name" asset_name : EnumProperty(name='', items=lambda s,c : ASSET_ITEMS) #asset_name : EnumProperty(name='', items=get_scene_settings().active_project.get('asset_items', [])) @classmethod def poll(cls, context): active_strip = context.scene.sequence_editor.active_strip if active_strip: return True def invoke(self, context, event): context.window_manager.invoke_search_popup(self) return {'FINISHED'} def execute(self, context): scn = context.scene settings = get_scene_settings() project = settings.active_project asset = project.assets[self.asset_name] strips = get_strips('Shots', selected_only=True) for strip in strips: #active_strip = scn.sequence_editor.active_strip strip_settings = strip.vsetb_strip_settings if strip_settings.casting.get(self.asset_name): self.report({'WARNING'}, f"Asset {asset.label} already casted.") return {"CANCELLED"} item = strip_settings.casting.add() item.name = asset.name item.id = asset.id item['_name'] = asset.label strip_settings.casting.update() self.report({"INFO"}, f'Item {asset.label} added in {len(strips)} shots') return {"FINISHED"} class VSETB_OT_casting_remove(Operator): bl_idname = "vse_toolbox.casting_remove" bl_label = "Remove Item from Casting" bl_description = "Remove Item from Casting" bl_options = {"REGISTER", "UNDO"} @classmethod def poll(cls, context): active_strip = context.scene.sequence_editor.active_strip if active_strip: return True def invoke(self, context, event): scn = context.scene settings = get_strip_settings() asset_id = settings.active_casting.id strips = get_strips('Shots', selected_only=True) strips_modified = 0 for strip in strips: strip_settings = strip.vsetb_strip_settings for i, asset_casting in enumerate(list(strip_settings.casting)): if asset_casting.id == asset_id: strip_settings.casting.remove(i) if strip_settings.casting_index != 0: strip_settings.casting_index -= 1 strips_modified += 1 continue if asset := settings.active_casting.asset: name = asset.label else: name = settings.active_casting.get('_name', '') self.report({"INFO"}, f'Item {name} removed in {strips_modified} shots') return {"FINISHED"} class VSETB_OT_casting_move(Operator): bl_idname = "vse_toolbox.casting_move" bl_label = "Move Casting items" bl_description = "Move Casting items" bl_options = {"REGISTER", "UNDO"} direction: EnumProperty( items=( ('UP', "Up", ""), ('DOWN', "Down", ""), ) ) asset_name : StringProperty() @classmethod def poll(cls, context): active_strip = context.scene.sequence_editor.active_strip if active_strip: return True def execute(self, context): scn = context.scene strip_settings = get_strip_settings() idx = strip_settings.casting_index try: item = strip_settings.casting[idx] except IndexError: pass else: if self.direction == 'DOWN' and idx < len(strip_settings.casting) - 1: item_next = strip_settings.casting[idx+1].name strip_settings.casting.move(idx, idx+1) strip_settings.casting_index += 1 elif self.direction == 'UP' and idx >= 1: item_prev = strip_settings.casting[idx-1].name strip_settings.casting.move(idx, idx-1) strip_settings.casting_index -= 1 info = f"Item {item.asset.label} moved to position {(item.asset.label, strip_settings.casting_index + 1)}" self.report({'INFO'}, info) return {"FINISHED"} class VSETB_OT_copy_casting(Operator): bl_idname = "vse_toolbox.copy_casting" bl_label = "Copy Casting" bl_description = "Copy Casting from active strip" bl_options = {"REGISTER", "UNDO"} @classmethod def poll(cls, context): active_strip = context.scene.sequence_editor.active_strip strip_settings = get_strip_settings() if active_strip and strip_settings.casting: return True def execute(self, context): scn = context.scene active_strip = scn.sequence_editor.active_strip strip_settings = get_strip_settings() datas = [c.to_dict() for c in strip_settings.casting] CASTING_BUFFER.write_text(json.dumps(datas), encoding='utf-8') return {"FINISHED"} class VSETB_OT_paste_casting(Operator): bl_idname = "vse_toolbox.paste_casting" bl_label = "Paste Casting" bl_description = "Paste Casting to active strip (ctrl|shift: Add, alt:Remove)" bl_options = {"REGISTER", "UNDO"} mode : EnumProperty(items=[(m, m.title(), '') for m in ('REPLACE', 'ADD', 'REMOVE')]) @classmethod def poll(cls, context): active_strip = context.scene.sequence_editor.active_strip if active_strip: return True def invoke(self, context, event): self.mode = 'REPLACE' if event.ctrl or event.shift: self.mode = 'ADD' elif event.alt: self.mode = 'REMOVE' return self.execute(context) def execute(self, context): scn = context.scene strip_settings = get_strip_settings() if not CASTING_BUFFER.exists(): self.report({'ERROR'}, f'No Casting to copy.') return {"CANCELLED"} casting_datas = json.loads(CASTING_BUFFER.read_text()) casting_ids = set(c['id'] for c in casting_datas) for strip in context.selected_sequences: strip_settings = strip.vsetb_strip_settings if self.mode == 'REPLACE': strip.vsetb_strip_settings.casting.clear() for casting_data in casting_datas: if self.mode == 'REMOVE': for asset_casting in strip_settings.casting: index = list(strip_settings.casting).index(asset_casting) if asset_casting.id in casting_ids: strip_settings.casting.remove(index) if strip_settings.casting_index != 0: strip_settings.casting_index -= 1 else: item = strip.vsetb_strip_settings.casting.add() item.name = casting_data['name'] item.id = casting_data['id'] item['_name'] = casting_data['_name'] strip_settings.casting.update() return {"FINISHED"} class VSETB_OT_copy_metadata(Operator): bl_idname = "vse_toolbox.copy_metadata" bl_label = "Copy metadata to selected" bl_description = "Copy Metadata to selected strips" metadata : StringProperty() @classmethod def poll(cls, context): return context.selected_sequences and context.active_sequence_strip def execute(self, context): prefs = get_addon_prefs() settings = get_scene_settings() project = settings.active_project metadata = next((m.field_name for m in project.metadata_types if m.name == self.metadata), None) if not metadata: self.report({'ERROR'}, f'No Metadata named {self.metadata}') active_strip = context.active_sequence_strip metadata_value = getattr(active_strip.vsetb_strip_settings.metadata, metadata) for strip in context.selected_sequences: if strip == context.active_sequence_strip: continue setattr(strip.vsetb_strip_settings.metadata, metadata, metadata_value) return {"FINISHED"} classes = ( VSETB_OT_casting_add, VSETB_OT_casting_remove, VSETB_OT_casting_move, VSETB_OT_copy_casting, VSETB_OT_paste_casting, VSETB_OT_casting_replace, VSETB_OT_copy_metadata ) def register(): for cls in classes: bpy.utils.register_class(cls) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls)