diff --git a/__init__.py b/__init__.py index aa3cb3c..cb01c6d 100644 --- a/__init__.py +++ b/__init__.py @@ -39,9 +39,6 @@ def register(): bpy.app.handlers.frame_change_post.append(update_text_strips) bpy.app.handlers.render_pre.append(update_text_strips) - if bpy.app.background: - return - for module in modules: module.register() @@ -60,9 +57,6 @@ def unregister(): # print(f"!-- {e} --!") # print(f"No preview collection found. {ASSET_PREVIEWS} can't be remove.") - if bpy.app.background: - return - bpy.app.handlers.frame_change_post.remove(set_active_strip) for module in reversed(modules): module.unregister() diff --git a/operators/imports.py b/operators/imports.py index c179623..73a4c28 100644 --- a/operators/imports.py +++ b/operators/imports.py @@ -2,21 +2,21 @@ from pathlib import Path import bpy -from bpy.types import Operator +from bpy.types import Operator, UIList from bpy.props import (CollectionProperty, BoolProperty, EnumProperty, StringProperty) from vse_toolbox.constants import (EDITS, EDIT_SUFFIXES, MOVIES, MOVIE_SUFFIXES, SOUNDS, SOUND_SUFFIXES) from vse_toolbox.sequencer_utils import (clean_sequencer, import_edit, import_movie, - import_sound, get_strips) + import_sound, get_strips, get_channel_index) from vse_toolbox.bl_utils import get_scene_settings from vse_toolbox.file_utils import install_module class VSETB_OT_auto_select_files(Operator): - bl_idname = "import.auto_select_files" + bl_idname = "vse_toolbox.auto_select_files" bl_label = "Auto Select" bl_description = "Auto Select Files" bl_options = {"REGISTER", "UNDO"} @@ -107,7 +107,7 @@ class VSETB_OT_import_files(Operator): layout.use_property_decorate = False col = layout.column(align=True) - col.operator('import.auto_select_files', text='Auto Select') + col.operator('vse_toolbox.auto_select_files', text='Auto Select') row = layout.row(heading="Import Edit", align=True) row.prop(self, 'import_edit') @@ -190,9 +190,102 @@ class VSETB_OT_import_files(Operator): return {"FINISHED"} +class VSETB_UL_import_task(UIList): + def draw_item(self, context, layout, data, item, icon, active_data, + active_propname, index): + + layout.prop(item, 'import_enabled', text='') + layout.label(text=item.name) + +class VSETB_OT_import_shots(Operator): + bl_idname = "vse_toolbox.import_shots" + bl_label = "Import Shots" + bl_description = "Import Shots for disk or tracker" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + return True + + def execute(self, context): + scn = context.scene + settings = get_scene_settings() + project = settings.active_project + + from gadget import Project + + p = Project.from_env() + p.shots.fetch() + + tasks = [t for t in project.task_types if t.import_enabled] + for i, task_type in enumerate(tasks): + channel_index = 9 + i + + scn.sequence_editor.channels[channel_index].name = task_type.name + + # Create Channels: + scn.sequence_editor.channels[9] + + for strip in get_strips('Shots'): + for i, task_type in enumerate(tasks): + shot = p.shots[strip.name] + versions = shot.tasks[task_type.name].outputs[0].versions.fetch() + + if versions: + print(versions[-1]) + + imported_strip = import_movie(versions[-1].path) + imported_strip.frame_start = strip.frame_start + + if imported_strip.frame_final_duration != strip.frame_final_duration: + print(f'strip {strip.name} has different duration') + imported_strip.color_tag = 'COLOR_03' + + imported_strip.frame_final_end = strip.frame_final_end + + imported_strip.channel = get_channel_index(task_type.name) + print(get_channel_index(task_type.name), imported_strip.channel) + else: + print(f'No movie for {strip.name} of task {task_type.name}') + + # for task_type in tasks: + # for strip in get_strips(task_type.name): + # strip.channel = get_channel_index(task_type.name) + + + return {'FINISHED'} + + def draw(self, context): + settings = get_scene_settings() + project = settings.active_project + + layout = self.layout + col = layout.column(align=False) + col.use_property_split = True + col.use_property_decorate = False + + row = col.row(align=True) + row.prop(project, "import_source", text='Source', expand=True) + + row = col.row(align=True) + row.prop(project, 'import_task', text='Import Tasks') + + if project.import_task == 'SELECTED': + col.use_property_split = False + col.template_list("VSETB_UL_import_task", "import_task", project, "task_types", project, "task_type_index", rows=8) + + def invoke(self, context, event): + scn = context.scene + settings = get_scene_settings() + project = settings.active_project + + return context.window_manager.invoke_props_dialog(self) + classes = ( + VSETB_UL_import_task, VSETB_OT_auto_select_files, VSETB_OT_import_files, + VSETB_OT_import_shots, ) def register(): diff --git a/operators/sequencer.py b/operators/sequencer.py index c2a270a..6af9e97 100644 --- a/operators/sequencer.py +++ b/operators/sequencer.py @@ -1,12 +1,12 @@ - +from os.path import expandvars import bpy from bpy.types import Operator from bpy.props import (BoolProperty, StringProperty) from vse_toolbox.sequencer_utils import (get_strips, rename_strips, set_channels, - get_channel_index, new_text_strip, get_strip_at) - -from vse_toolbox.bl_utils import get_scene_settings + get_channel_index, new_text_strip, get_strip_at, get_channel_name) + +from vse_toolbox.bl_utils import get_scene_settings, get_strip_settings class VSETB_OT_rename(Operator): @@ -269,6 +269,32 @@ class VSETB_OT_next_shot(Operator): return {"FINISHED"} +class VSETB_OT_open_shot_dir(Operator): + bl_idname = "vse_toolbox.open_shot_dir" + bl_label = "Open Shot Dir" + bl_description = "Open Shot Dir" + bl_options = {"REGISTER", "UNDO"} + + @classmethod + def poll(cls, context): + strip = context.active_sequence_strip + return strip and get_channel_name(strip) == 'Shots' + + def execute(self, context): + strip = context.active_sequence_strip + settings = get_scene_settings() + project = settings.active_project + + strip_settings = get_strip_settings() + + format_data = {**settings.format_data, **project.format_data, **strip_settings.format_data} + + shot_dir_template = expandvars(project.shot_dir_template) + shot_dir_path = shot_dir_template.format(**format_data) + bpy.ops.wm.path_open(filepath=shot_dir_path) + + return {"FINISHED"} + addon_keymaps = [] def register_keymaps(): @@ -304,7 +330,8 @@ classes = ( VSETB_OT_set_stamps, VSETB_OT_show_waveform, VSETB_OT_previous_shot, - VSETB_OT_next_shot + VSETB_OT_next_shot, + VSETB_OT_open_shot_dir ) def register(): diff --git a/ui/panels.py b/ui/panels.py index a83c837..c6ed0dd 100644 --- a/ui/panels.py +++ b/ui/panels.py @@ -3,7 +3,7 @@ from pathlib import Path import bpy -from bpy.types import Panel +from bpy.types import Panel, Menu from bl_ui.utils import PresetPanel from vse_toolbox.bl_utils import (get_addon_prefs, get_scene_settings, get_strip_settings) @@ -185,6 +185,7 @@ class VSETB_PT_imports(VSETB_main, Panel): #row = col.row(align=True) #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") class VSETB_PT_presets(PresetPanel, Panel): @@ -396,6 +397,20 @@ def context_menu_prop(self, context): layout.operator('vse_toolbox.copy_metadata', icon='PASTEDOWN', text='Copy metadata to selected').metadata = button_prop.name +class VSETB_MT_main_menu(Menu): + bl_label = "Vse Toolbox" + + def draw(self, context): + layout = self.layout + + layout.operator('vse_toolbox.open_shot_dir', text='Open Shot', icon='FILE_FOLDER') + + +def draw_vse_toolbox_menu(self, context): + self.layout.menu("VSETB_MT_main_menu") + + + classes = ( VSETB_PT_main, VSETB_PT_imports, @@ -406,7 +421,8 @@ classes = ( VSETB_PT_comments, VSETB_PT_presets, VSETB_PT_exports, - VSETB_PT_strip + VSETB_PT_strip, + VSETB_MT_main_menu ) def register(): @@ -414,9 +430,11 @@ def register(): bpy.utils.register_class(cls) bpy.types.UI_MT_button_context_menu.append(context_menu_prop) + bpy.types.SEQUENCER_MT_editor_menus.append(draw_vse_toolbox_menu) def unregister(): for cls in reversed(classes): bpy.utils.unregister_class(cls) - bpy.types.UI_MT_button_context_menu.remove(context_menu_prop) \ No newline at end of file + bpy.types.UI_MT_button_context_menu.remove(context_menu_prop) + bpy.types.SEQUENCER_MT_editor_menus.remove(draw_vse_toolbox_menu) \ No newline at end of file diff --git a/ui/properties.py b/ui/properties.py index 1957b9f..0b2caa6 100644 --- a/ui/properties.py +++ b/ui/properties.py @@ -109,6 +109,7 @@ class MetadataType(PropertyGroup): class TaskType(PropertyGroup): color : FloatVectorProperty(subtype='COLOR') + import_enabled : BoolProperty(default=False) class TaskStatus(PropertyGroup): @@ -297,6 +298,7 @@ class Project(PropertyGroup): asset_types : CollectionProperty(type=AssetType) metadata_types : CollectionProperty(type=MetadataType) task_types : CollectionProperty(type=TaskType) + task_type_index : IntProperty() task_statuses : CollectionProperty(type=TaskStatus) spreadsheet_import: PointerProperty(type=SpreadsheetImport) @@ -304,6 +306,12 @@ class Project(PropertyGroup): type : StringProperty() + import_source: EnumProperty(items=[(i, i.title(), '') for i in ('DISK', 'TRACKER')]) + import_task: EnumProperty(items=[(i, i.title(), '') for i in ('LAST', 'SELECTED', 'ALL')], default='LAST') + + shot_dir_template: StringProperty( + name="Shot Template", default="$PROJECT_ROOT/sequences/{sequence}/sh{index:04d}") + @property def active_episode(self): return self.episodes.get(self.episode_name) @@ -582,7 +590,7 @@ class VSETB_PGT_scene_settings(PropertyGroup): shot_channel_name : StringProperty( name="Shot Channel Name", default="Shots") - + @property def active_project(self): settings = get_scene_settings()