Blender_Kitsu & Render Review: Remove Metastrip Filepath #80

Merged
Nick Alberelli merged 2 commits from fix/meta-strip-file-path into main 2023-06-15 21:28:34 +02:00
3 changed files with 106 additions and 122 deletions

View File

@ -154,10 +154,6 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
return "" return ""
return self.project_root_path.joinpath("pipeline/blender_kitsu").as_posix() return self.project_root_path.joinpath("pipeline/blender_kitsu").as_posix()
def get_metastrip_file(self) -> str:
res_dir = bkglobals.RES_DIR_PATH
return res_dir.joinpath("metastrip.mp4").as_posix()
def init_playblast_file_model(self, context: bpy.types.Context) -> None: def init_playblast_file_model(self, context: bpy.types.Context) -> None:
ops_playblast_data.init_playblast_file_model(context) ops_playblast_data.init_playblast_file_model(context)
@ -228,16 +224,6 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
get=get_config_dir, get=get_config_dir,
) )
metastrip_file: bpy.props.StringProperty( # type: ignore
name="Meta Strip File",
description=(
"Filepath to black .mp4 file that will be used as metastrip for shots in the sequence editor"
),
default="",
subtype="FILE_PATH",
get=get_metastrip_file,
)
project_active_id: bpy.props.StringProperty( # type: ignore project_active_id: bpy.props.StringProperty( # type: ignore
name="Project Active ID", name="Project Active ID",
description="Server Id that refers to the last active project", description="Server Id that refers to the last active project",
@ -252,7 +238,7 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
name="Show Advanced Settings", name="Show Advanced Settings",
description="Show advanced settings that should already have good defaults", description="Show advanced settings that should already have good defaults",
) )
shot_builder_show_advanced : bpy.props.BoolProperty( # type: ignore shot_builder_show_advanced: bpy.props.BoolProperty( # type: ignore
name="Show Advanced Settings", name="Show Advanced Settings",
description="Show advanced settings that should already have good defaults", description="Show advanced settings that should already have good defaults",
) )
@ -313,13 +299,12 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
options={"HIDDEN", "SKIP_SAVE"}, options={"HIDDEN", "SKIP_SAVE"},
description="File pattern to search for latest editorial export. Typically '{proj_name}_v\d\d\d.mp4'", description="File pattern to search for latest editorial export. Typically '{proj_name}_v\d\d\d.mp4'",
default="petprojects_v\d\d\d.mp4", default="petprojects_v\d\d\d.mp4",
) )
edit_export_frame_offset: bpy.props.IntProperty( # type: ignore edit_export_frame_offset: bpy.props.IntProperty( # type: ignore
name="Editorial Export Offset", name="Editorial Export Offset",
description="Shift Editorial Export by this frame-range after set-up.", description="Shift Editorial Export by this frame-range after set-up.",
default=-102, #HARD CODED FOR PET PROJECTS BLENDER FILM default=-102, # HARD CODED FOR PET PROJECTS BLENDER FILM
) )
shot_builder_frame_offset: bpy.props.IntProperty( # type: ignore shot_builder_frame_offset: bpy.props.IntProperty( # type: ignore
@ -340,7 +325,7 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
default="ANI-", default="ANI-",
) )
user_exec_code: bpy.props.StringProperty(# type: ignore user_exec_code: bpy.props.StringProperty( # type: ignore
name="Post Execution Command", name="Post Execution Command",
description="Run this command after shot_builder is complete, but before the file is saved.", description="Run this command after shot_builder is complete, but before the file is saved.",
default="", default="",
@ -424,7 +409,7 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
icon="ADD", icon="ADD",
emboss=False, emboss=False,
) )
# Shot_Builder settings. # Shot_Builder settings.
box = layout.box() box = layout.box()
box.label(text="Shot Builder", icon="MOD_BUILD") box.label(text="Shot Builder", icon="MOD_BUILD")
@ -437,7 +422,7 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
start_frame_row.label(text="Start Frame Offset") start_frame_row.label(text="Start Frame Offset")
start_frame_row.prop(self, "shot_builder_frame_offset", text="") start_frame_row.prop(self, "shot_builder_frame_offset", text="")
box.row().prop(self, "shot_builder_armature_prefix") box.row().prop(self, "shot_builder_armature_prefix")
box.row().prop(self, "shot_builder_action_prefix") box.row().prop(self, "shot_builder_action_prefix")
box.row().prop(self, "user_exec_code") box.row().prop(self, "user_exec_code")
# Misc settings. # Misc settings.
@ -453,7 +438,6 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
box.row().prop(self, "shot_counter_digits") box.row().prop(self, "shot_counter_digits")
box.row().prop(self, "shot_counter_increment") box.row().prop(self, "shot_counter_increment")
@property @property
def playblast_root_path(self) -> Optional[Path]: def playblast_root_path(self) -> Optional[Path]:
if not self.is_playblast_root_valid: if not self.is_playblast_root_valid:
@ -495,16 +479,17 @@ class KITSU_addon_preferences(bpy.types.AddonPreferences):
return False return False
return True return True
@property @property
def is_editorial_dir_valid(self) -> bool: def is_editorial_dir_valid(self) -> bool:
if editorial_export_check_latest(bpy.context) is None: if editorial_export_check_latest(bpy.context) is None:
logger.error( logger.error(
"Failed to initialize editorial export file model. Invalid path/pattern. Check addon preferences" "Failed to initialize editorial export file model. Invalid path/pattern. Check addon preferences"
) )
return False return False
return True return True
def session_get(context: bpy.types.Context) -> Session: def session_get(context: bpy.types.Context) -> Session:
""" """
Shortcut to get session from blender_kitsu addon preferences Shortcut to get session from blender_kitsu addon preferences
@ -544,7 +529,6 @@ def register():
def unregister(): def unregister():
# Log user out. # Log user out.
addon_prefs = bpy.context.preferences.addons["blender_kitsu"].preferences addon_prefs = bpy.context.preferences.addons["blender_kitsu"].preferences
if addon_prefs.session.is_auth(): if addon_prefs.session.is_auth():

View File

@ -172,7 +172,6 @@ class KITSU_OT_sqe_push_new_shot(bpy.types.Operator):
return bool(prefs.session_auth(context) and cache.project_active_get()) return bool(prefs.session_auth(context) and cache.project_active_get())
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
if not self.confirm: if not self.confirm:
self.report({"WARNING"}, "Submit new shots aborted") self.report({"WARNING"}, "Submit new shots aborted")
return {"CANCELLED"} return {"CANCELLED"}
@ -309,6 +308,7 @@ class KITSU_OT_sqe_push_new_shot(bpy.types.Operator):
% (noun.lower()), % (noun.lower()),
) )
class KITSU_OT_sqe_push_new_sequence(bpy.types.Operator): class KITSU_OT_sqe_push_new_sequence(bpy.types.Operator):
bl_idname = "kitsu.sqe_push_new_sequence" bl_idname = "kitsu.sqe_push_new_sequence"
bl_label = "Submit New Sequence" bl_label = "Submit New Sequence"
@ -327,7 +327,6 @@ class KITSU_OT_sqe_push_new_sequence(bpy.types.Operator):
return bool(prefs.session_auth(context) and cache.project_active_get()) return bool(prefs.session_auth(context) and cache.project_active_get())
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
if not self.confirm: if not self.confirm:
self.report({"WARNING"}, "Submit new sequence aborted") self.report({"WARNING"}, "Submit new sequence aborted")
return {"CANCELLED"} return {"CANCELLED"}
@ -420,7 +419,6 @@ class KITSU_OT_sqe_init_strip(bpy.types.Operator):
) )
for strip in selected_sequences: for strip in selected_sequences:
if not checkstrip.is_valid_type(strip): if not checkstrip.is_valid_type(strip):
continue continue
@ -621,7 +619,6 @@ class KITSU_OT_sqe_link_shot(bpy.types.Operator):
class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator): class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
bl_idname = "kitsu.sqe_multi_edit_strip" bl_idname = "kitsu.sqe_multi_edit_strip"
bl_label = "Multi Edit Strip" bl_label = "Multi Edit Strip"
bl_options = {"INTERNAL"} bl_options = {"INTERNAL"}
@ -685,7 +682,6 @@ class KITSU_OT_sqe_multi_edit_strip(bpy.types.Operator):
) )
for idx, strip in enumerate(selected_sequences): for idx, strip in enumerate(selected_sequences):
# Gen data for resolver. # Gen data for resolver.
counter_number = shot_counter_start + (shot_counter_increment * idx) counter_number = shot_counter_start + (shot_counter_increment * idx)
counter = str(counter_number).rjust(shot_counter_digits, "0") counter = str(counter_number).rjust(shot_counter_digits, "0")
@ -852,7 +848,6 @@ class KITSU_OT_sqe_uninit_strip(bpy.types.Operator):
logger.info("-START- Uninitializing strips") logger.info("-START- Uninitializing strips")
for strip in context.selected_sequences: for strip in context.selected_sequences:
if not checkstrip.is_valid_type(strip): if not checkstrip.is_valid_type(strip):
continue continue
@ -905,7 +900,6 @@ class KITSU_OT_sqe_unlink_shot(bpy.types.Operator):
logger.info("-START- Unlinking shots") logger.info("-START- Unlinking shots")
for strip in context.selected_sequences: for strip in context.selected_sequences:
if not checkstrip.is_valid_type(strip): if not checkstrip.is_valid_type(strip):
continue continue
@ -1047,7 +1041,6 @@ class KITSU_OT_sqe_set_thumbnail_task_type(bpy.types.Operator):
return bool(prefs.session_auth(context) and cache.project_active_get()) return bool(prefs.session_auth(context) and cache.project_active_get())
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
# Task type selected by user. # Task type selected by user.
task_type_id = self.enum_prop task_type_id = self.enum_prop
@ -1084,7 +1077,6 @@ class KITSU_OT_sqe_set_sqe_render_task_type(bpy.types.Operator):
return bool(prefs.session_auth(context) and cache.project_active_get()) return bool(prefs.session_auth(context) and cache.project_active_get())
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
# Task type selected by user. # Task type selected by user.
task_type_id = self.enum_prop task_type_id = self.enum_prop
@ -1135,7 +1127,6 @@ class KITSU_OT_sqe_push_thumbnail(bpy.types.Operator):
with self.override_render_settings(context): with self.override_render_settings(context):
with self.temporary_current_frame(context) as original_curframe: with self.temporary_current_frame(context) as original_curframe:
# ----RENDER AND SAVE THUMBNAILS ------. # ----RENDER AND SAVE THUMBNAILS ------.
# Begin first progress update. # Begin first progress update.
@ -1320,7 +1311,6 @@ class KITSU_OT_sqe_push_render(bpy.types.Operator):
Cache.clear_all() Cache.clear_all()
with self.override_render_settings(context): with self.override_render_settings(context):
# ----RENDER AND SAVE SQE ------. # ----RENDER AND SAVE SQE ------.
# Get strips. # Get strips.
@ -1404,13 +1394,12 @@ class KITSU_OT_sqe_push_render(bpy.types.Operator):
# Log. # Log.
logger.info("-END- Pushing Sequence Editor Render") logger.info("-END- Pushing Sequence Editor Render")
return {"FINISHED"} return {"FINISHED"}
def _gen_output_path(self, strip: bpy.types.Sequence, task_type: TaskType) -> Path: def _gen_output_path(self, strip: bpy.types.Sequence, task_type: TaskType) -> Path:
addon_prefs = prefs.addon_prefs_get(bpy.context) addon_prefs = prefs.addon_prefs_get(bpy.context)
folder_name = addon_prefs.sqe_render_dir folder_name = addon_prefs.sqe_render_dir
file_name = f"{strip.kitsu.shot_id}_{strip.kitsu.shot_name}.{(task_type.name).lower()}.mp4" file_name = f"{strip.kitsu.shot_id}_{strip.kitsu.shot_name}.{(task_type.name).lower()}.mp4"
return Path(folder_name).absolute().joinpath(file_name) return Path(folder_name).absolute().joinpath(file_name)
@contextlib.contextmanager @contextlib.contextmanager
def override_render_settings(self, context, thumbnail_width=256): def override_render_settings(self, context, thumbnail_width=256):
@ -1473,9 +1462,7 @@ class KITSU_OT_sqe_push_render(bpy.types.Operator):
class KITSU_OT_sqe_push_shot(bpy.types.Operator): class KITSU_OT_sqe_push_shot(bpy.types.Operator):
bl_idname = "kitsu.sqe_push_shot" bl_idname = "kitsu.sqe_push_shot"
bl_label = "Push Shot to Kitsu" bl_label = "Push Shot to Kitsu"
bl_description = ( bl_description = "Pushes the active strip to Kitsu"
"Pushes the active strip to Kitsu"
)
comment: bpy.props.StringProperty( comment: bpy.props.StringProperty(
name="Comment", name="Comment",
@ -1483,14 +1470,14 @@ class KITSU_OT_sqe_push_shot(bpy.types.Operator):
default="", default="",
) )
task_type: bpy.props.EnumProperty( task_type: bpy.props.EnumProperty(
name = "Task Type", name="Task Type",
description = "Which task this video should be added to", description="Which task this video should be added to",
items = cache.get_task_types_enum_for_current_context items=cache.get_task_types_enum_for_current_context,
) )
task_status: bpy.props.EnumProperty( task_status: bpy.props.EnumProperty(
name = "Task Status", name="Task Status",
description = "What to set the task's status to", description="What to set the task's status to",
items = cache.get_all_task_statuses_enum items=cache.get_all_task_statuses_enum,
) )
@classmethod @classmethod
@ -1499,9 +1486,7 @@ class KITSU_OT_sqe_push_shot(bpy.types.Operator):
if not hasattr(active_strip, 'filepath'): if not hasattr(active_strip, 'filepath'):
return False return False
return bool( return bool(prefs.session_auth(context))
prefs.session_auth(context)
)
def invoke(self, context, _event): def invoke(self, context, _event):
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
@ -1523,8 +1508,8 @@ class KITSU_OT_sqe_push_shot(bpy.types.Operator):
shot_name = active_strip.name.split(".")[0] shot_name = active_strip.name.split(".")[0]
metastrip = context.scene.sequence_editor.sequences.get(shot_name) metastrip = context.scene.sequence_editor.sequences.get(shot_name)
if not metastrip: if not metastrip:
# The metastrip should've been created by sqe_create_review_session, # The metastrip should've been created by sqe_create_review_session,
# if the Kitsu integration is enabled in the add-on preferences, # if the Kitsu integration is enabled in the add-on preferences,
# the Kitsu add-on is enabled, and valid Kitsu credentials were entered. # the Kitsu add-on is enabled, and valid Kitsu credentials were entered.
self.report({"ERROR"}, f"Could not find Kitsu metastrip: {shot_name}.") self.report({"ERROR"}, f"Could not find Kitsu metastrip: {shot_name}.")
return {"CANCELLED"} return {"CANCELLED"}
@ -1707,11 +1692,7 @@ class KITSU_OT_sqe_pull_edit(bpy.types.Operator):
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
addon_prefs = prefs.addon_prefs_get(context) addon_prefs = prefs.addon_prefs_get(context)
return bool( return bool(prefs.session_auth(context) and cache.project_active_get())
prefs.session_auth(context)
and cache.project_active_get()
and addon_prefs.metastrip_file
)
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
addon_prefs = prefs.addon_prefs_get(context) addon_prefs = prefs.addon_prefs_get(context)
@ -1791,12 +1772,12 @@ class KITSU_OT_sqe_pull_edit(bpy.types.Operator):
frame_end, frame_end,
) )
continue continue
# TODO Refactor as this reuses code from KITSU_OT_sqe_create_meta_strip
if not strip: if not strip:
# Create new strip. # Create new strip.
strip = context.scene.sequence_editor.sequences.new_movie( strip = context.scene.sequence_editor.sequences.new_movie(
shot.name, shot.name,
addon_prefs.metastrip_file, "",
channel, channel,
frame_start, frame_start,
) )
@ -1912,7 +1893,6 @@ class KITSU_OT_sqe_pull_edit(bpy.types.Operator):
class KITSU_OT_sqe_init_strip_start_frame(bpy.types.Operator): class KITSU_OT_sqe_init_strip_start_frame(bpy.types.Operator):
bl_idname = "kitsu.sqe_init_strip_start_frame" bl_idname = "kitsu.sqe_init_strip_start_frame"
bl_label = "Initialize Shot Start Frame" bl_label = "Initialize Shot Start Frame"
bl_description = "Calculates offset so the current shot starts at 101" bl_description = "Calculates offset so the current shot starts at 101"
@ -1932,7 +1912,6 @@ class KITSU_OT_sqe_init_strip_start_frame(bpy.types.Operator):
selected_sequences = context.scene.sequence_editor.sequences_all selected_sequences = context.scene.sequence_editor.sequences_all
for strip in selected_sequences: for strip in selected_sequences:
if not checkstrip.is_valid_type(strip): if not checkstrip.is_valid_type(strip):
continue continue
@ -1981,7 +1960,7 @@ class KITSU_OT_sqe_create_meta_strip(bpy.types.Operator):
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
addon_prefs = prefs.addon_prefs_get(context) addon_prefs = prefs.addon_prefs_get(context)
return bool(context.selected_sequences and addon_prefs.metastrip_file) return bool(context.selected_sequences)
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
addon_prefs = prefs.addon_prefs_get(context) addon_prefs = prefs.addon_prefs_get(context)
@ -1993,15 +1972,7 @@ class KITSU_OT_sqe_create_meta_strip(bpy.types.Operator):
selected_sequences = context.selected_sequences selected_sequences = context.selected_sequences
# Check if metastrip file actually exists. # Check if metastrip file actually exists.
if not Path(addon_prefs.metastrip_file).exists():
self.report(
{"ERROR"},
f"Failed to load metastrip file: {addon_prefs.metastrip_file}. Path does not exist",
)
return {"CANCELLED"}
for strip in selected_sequences: for strip in selected_sequences:
# Get frame range information from current strip. # Get frame range information from current strip.
strip_range = range(strip.frame_final_start, strip.frame_final_end) strip_range = range(strip.frame_final_start, strip.frame_final_end)
channel = strip.channel + 1 channel = strip.channel + 1
@ -2026,7 +1997,7 @@ class KITSU_OT_sqe_create_meta_strip(bpy.types.Operator):
# on the first try, EDIT: seems to work maybe per python overlaps of sequences possible? # on the first try, EDIT: seems to work maybe per python overlaps of sequences possible?
meta_strip = context.scene.sequence_editor.sequences.new_movie( meta_strip = context.scene.sequence_editor.sequences.new_movie(
f"{strip.name}_metastrip", f"{strip.name}_metastrip",
addon_prefs.metastrip_file, "",
strip.channel + 1, strip.channel + 1,
strip.frame_final_start, strip.frame_final_start,
) )
@ -2117,7 +2088,8 @@ class KITSU_OT_sqe_scan_for_media_updates(bpy.types.Operator):
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
sqe = context.scene.sequence_editor sqe = context.scene.sequence_editor
if not sqe: return False if not sqe:
return False
return bool(sqe.sequences_all) return bool(sqe.sequences_all)
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
@ -2136,7 +2108,6 @@ class KITSU_OT_sqe_scan_for_media_updates(bpy.types.Operator):
logger.info("-START- Scanning for media updates") logger.info("-START- Scanning for media updates")
for strip in sequences: for strip in sequences:
if not strip.type == "MOVIE": if not strip.type == "MOVIE":
continue continue
@ -2253,7 +2224,6 @@ class KITSU_OT_sqe_clear_update_indicators(bpy.types.Operator):
sequences = context.scene.sequence_editor.sequences_all sequences = context.scene.sequence_editor.sequences_all
for strip in sequences: for strip in sequences:
if strip.kitsu.media_outdated: if strip.kitsu.media_outdated:
strip.kitsu.media_outdated = False strip.kitsu.media_outdated = False
reset.append(strip) reset.append(strip)
@ -2400,32 +2370,40 @@ class KITSU_OT_sqe_change_strip_source(bpy.types.Operator):
util.ui_redraw() util.ui_redraw()
return {"FINISHED"} return {"FINISHED"}
def set_entity_data(entity, key: str, value: int): def set_entity_data(entity, key: str, value: int):
if get_entity_data(entity, key) is not None: if get_entity_data(entity, key) is not None:
entity['data'][key] = value entity['data'][key] = value
return entity return entity
def get_entity_data(entity, key: str): def get_entity_data(entity, key: str):
if entity.get("data").get(key) is not None: if entity.get("data").get(key) is not None:
return entity.get("data").get(key) return entity.get("data").get(key)
def get_dict_len(items:dict):
def get_dict_len(items: dict):
try: try:
return len(items) return len(items)
except TypeError: except TypeError:
return None return None
def set_revision_int(prev_rev=None): def set_revision_int(prev_rev=None):
if prev_rev is None: if prev_rev is None:
return 1 return 1
return prev_rev+1 return prev_rev + 1
class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator): class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator):
bl_idname = "kitsu.vse_publish_edit_revision" bl_idname = "kitsu.vse_publish_edit_revision"
bl_label = "Render and 'Publish as Revision'" bl_label = "Render and 'Publish as Revision'"
bl_description = "Renders current VSE Edit as .mp4 and publishes as revision on 'Edit Task'.\nWill not overwrite existing files" bl_description = "Renders current VSE Edit as .mp4 and publishes as revision on 'Edit Task'.\nWill not overwrite existing files"
def get_edit_entry_items(self: Any, context: bpy.types.Context) -> List[Tuple[str, str, str]]: def get_edit_entry_items(
self: Any, context: bpy.types.Context
) -> List[Tuple[str, str, str]]:
sorted_edits = [] sorted_edits = []
active_project = cache.project_active_get() active_project = cache.project_active_get()
@ -2433,45 +2411,68 @@ class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator):
if (edit["project_id"] == active_project.id) and not edit['canceled']: if (edit["project_id"] == active_project.id) and not edit['canceled']:
sorted_edits.append(edit) sorted_edits.append(edit)
return [(item.get("id"), item.get("name"), f'Created at: "{item.get("created_at")}" {item.get("description")}') for item in sorted_edits] return [
(
item.get("id"),
item.get("name"),
f'Created at: "{item.get("created_at")}" {item.get("description")}',
)
for item in sorted_edits
]
def get_edit_task_items(self: Any, context: bpy.types.Context) -> List[Tuple[str, str, str]]: def get_edit_task_items(
self: Any, context: bpy.types.Context
) -> List[Tuple[str, str, str]]:
tasks = gazu.task.all_tasks_for_edit(self.edit_entry) tasks = gazu.task.all_tasks_for_edit(self.edit_entry)
return [(item.get("id"), item.get("name"), f'Created at: "{item.get("created_at")}" {item.get("description")}') for item in tasks] return [
(
item.get("id"),
item.get("name"),
f'Created at: "{item.get("created_at")}" {item.get("description")}',
)
for item in tasks
]
comment: bpy.props.StringProperty(name="Comment") comment: bpy.props.StringProperty(name="Comment")
edit_entry: bpy.props.EnumProperty(name="Edit", items=get_edit_entry_items) edit_entry: bpy.props.EnumProperty(name="Edit", items=get_edit_entry_items)
task: bpy.props.EnumProperty(name="Edit", items=get_edit_task_items) task: bpy.props.EnumProperty(name="Edit", items=get_edit_task_items)
render_dir: bpy.props.StringProperty( render_dir: bpy.props.StringProperty(
name="Folder", name="Folder",
subtype="DIR_PATH", subtype="DIR_PATH",
) )
use_frame_start: bpy.props.BoolProperty(name="Submit update to 'frame_start'.", default=False) use_frame_start: bpy.props.BoolProperty(
frame_start: bpy.props.IntProperty(name="Frame Start", description="Send an integerfor the 'frame_start' value of the current Kitsu Edit. \nThis is used by Watchtower to pad the edit in the timeline.", default=0) name="Submit update to 'frame_start'.", default=False
)
frame_start: bpy.props.IntProperty(
name="Frame Start",
description="Send an integerfor the 'frame_start' value of the current Kitsu Edit. \nThis is used by Watchtower to pad the edit in the timeline.",
default=0,
)
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
return bool( return bool(prefs.session_auth(context) and cache.project_active_get())
prefs.session_auth(context)
and cache.project_active_get()
)
def invoke(self, context, event): def invoke(self, context, event):
# Ensure user has permissions to access edit data # Ensure user has permissions to access edit data
try: try:
edits = gazu.edit.get_all_edits_with_tasks() edits = gazu.edit.get_all_edits_with_tasks()
except gazu.exception.NotAllowedException: except gazu.exception.NotAllowedException:
self.report({"ERROR"}, "Kitsu User doesn't have permissions to access edit data.") self.report(
return {"CANCELLED"} {"ERROR"}, "Kitsu User doesn't have permissions to access edit data."
)
return {"CANCELLED"}
# Remove file name if set in render.filepath # Remove file name if set in render.filepath
dir_path = bpy.path.abspath(context.scene.render.filepath) dir_path = bpy.path.abspath(context.scene.render.filepath)
if not os.path.isdir(Path(dir_path)): if not os.path.isdir(Path(dir_path)):
dir_path = Path(dir_path).parent dir_path = Path(dir_path).parent
self.render_dir = str(dir_path) self.render_dir = str(dir_path)
#'frame_start' is optionally property appearring on all edit_entries for a project if it exists #'frame_start' is optionally property appearring on all edit_entries for a project if it exists
server_frame_start = get_entity_data(gazu.edit.get_edit(self.edit_entry), 'frame_start') server_frame_start = get_entity_data(
gazu.edit.get_edit(self.edit_entry), 'frame_start'
)
if server_frame_start is int: if server_frame_start is int:
self.frame_start = server_frame_start self.frame_start = server_frame_start
self.use_frame_start = bool(server_frame_start is not None) self.use_frame_start = bool(server_frame_start is not None)
@ -2488,11 +2489,12 @@ class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator):
# Only set `frame_start` if exists on current project # Only set `frame_start` if exists on current project
if self.use_frame_start: if self.use_frame_start:
layout.prop(self, "frame_start") layout.prop(self, "frame_start")
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
if self.task == "": if self.task == "":
self.report({"ERROR"}, "Selected edit doesn't have any task associated with it .") self.report(
{"ERROR"}, "Selected edit doesn't have any task associated with it ."
)
return {"CANCELLED"} return {"CANCELLED"}
active_project = cache.project_active_get() active_project = cache.project_active_get()
@ -2505,9 +2507,8 @@ class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator):
render_dir = bpy.path.abspath(self.render_dir) render_dir = bpy.path.abspath(self.render_dir)
if not os.path.isdir(Path(render_dir)): if not os.path.isdir(Path(render_dir)):
self.report( self.report(
{"ERROR"}, {"ERROR"}, f"Render path is not set to a directory. '{self.render_dir}'"
f"Render path is not set to a directory. '{self.render_dir}'" )
)
return {"CANCELLED"} return {"CANCELLED"}
edit_entry = gazu.edit.get_edit(self.edit_entry) edit_entry = gazu.edit.get_edit(self.edit_entry)
prod_name = active_project.name.lower().replace(' ', '') prod_name = active_project.name.lower().replace(' ', '')
@ -2516,33 +2517,35 @@ class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator):
# check path exists # check path exists
if render_path.is_file(): if render_path.is_file():
self.report( self.report(
{"ERROR"}, {"ERROR"}, f"File '{render_name}' already exists at '{self.render_dir}'"
f"File '{render_name}' already exists at '{self.render_dir}'" )
)
return {"CANCELLED"} return {"CANCELLED"}
# Render Sequence to .mp4 # Render Sequence to .mp4
with override_render_path(self, context, render_path.as_posix()): with override_render_path(self, context, render_path.as_posix()):
with override_render_format(self, context): with override_render_format(self, context):
bpy.ops.render.opengl(animation=True, sequencer=True) bpy.ops.render.opengl(animation=True, sequencer=True)
# Create comment with video # Create comment with video
task_entity = gazu.task.get_task(self.task) task_entity = gazu.task.get_task(self.task)
new_comment = gazu.task.add_comment(task_entity, task_entity["task_status"], self.comment) new_comment = gazu.task.add_comment(
task_entity, task_entity["task_status"], self.comment
)
new_preview = gazu.task.add_preview(task_entity, new_comment, render_path) new_preview = gazu.task.add_preview(task_entity, new_comment, render_path)
# Update edit_entry's frame_start if 'frame_start' is found on server # Update edit_entry's frame_start if 'frame_start' is found on server
if self.use_frame_start: if self.use_frame_start:
edit_entity_update = set_entity_data(edit_entry, 'frame_start', self.frame_start) edit_entity_update = set_entity_data(
updated_edit_entity = gazu.entity.update_entity(edit_entity_update) #TODO add a generic function to update entites edit_entry, 'frame_start', self.frame_start
)
updated_edit_entity = gazu.entity.update_entity(
edit_entity_update
) # TODO add a generic function to update entites
self.report({"INFO"}, f"Submitted new comment 'Revision {revision}'")
self.report(
{"INFO"},
f"Submitted new comment 'Revision {revision}'"
)
return {"FINISHED"} return {"FINISHED"}
# ---------REGISTER ----------. # ---------REGISTER ----------.
classes = [ classes = [
@ -2573,7 +2576,6 @@ classes = [
KITSU_OT_sqe_change_strip_source, KITSU_OT_sqe_change_strip_source,
KITSU_OT_sqe_clear_update_indicators, KITSU_OT_sqe_clear_update_indicators,
KITSU_OT_vse_publish_edit_revision, KITSU_OT_vse_publish_edit_revision,
] ]

View File

@ -55,7 +55,6 @@ def addon_prefs() -> bpy.types.AddonPreferences:
def create_meta_strip( def create_meta_strip(
context: bpy.types.Context, strip: bpy.types.Sequence context: bpy.types.Context, strip: bpy.types.Sequence
) -> bpy.types.MovieSequence: ) -> bpy.types.MovieSequence:
# Get frame range information from current strip. # Get frame range information from current strip.
strip_range = range(strip.frame_final_start, strip.frame_final_end) strip_range = range(strip.frame_final_start, strip.frame_final_end)
channel = strip.channel + 1 channel = strip.channel + 1
@ -63,7 +62,7 @@ def create_meta_strip(
# Create new meta strip. # Create new meta strip.
meta_strip = context.scene.sequence_editor.sequences.new_movie( meta_strip = context.scene.sequence_editor.sequences.new_movie(
f"{strip.name}_metastrip", f"{strip.name}_metastrip",
addon_prefs().metastrip_file, "",
strip.channel + 1, strip.channel + 1,
strip.frame_final_start, strip.frame_final_start,
) )
@ -94,7 +93,6 @@ def link_strip_by_name(
shot_name: str, shot_name: str,
sequence_name: str, sequence_name: str,
) -> None: ) -> None:
# Get seq and shot. # Get seq and shot.
active_project = cache.project_active_get() active_project = cache.project_active_get()
seq = active_project.get_sequence_by_name(sequence_name) seq = active_project.get_sequence_by_name(sequence_name)