Render Review: Fix Import Errors #122

Merged
Nick Alberelli merged 4 commits from :fix/render-review-import-errors into main 2023-07-13 19:44:15 +02:00

View File

@ -29,6 +29,7 @@ from collections import OrderedDict
import bpy import bpy
from render_review import vars, prefs, opsdata, util, kitsu from render_review import vars, prefs, opsdata, util, kitsu
if prefs.is_blender_kitsu_enabled(): if prefs.is_blender_kitsu_enabled():
from blender_kitsu import types as kitsu_types from blender_kitsu import types as kitsu_types
from blender_kitsu import cache from blender_kitsu import cache
@ -68,7 +69,9 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
or opsdata.is_sequence_dir(render_dir) or opsdata.is_sequence_dir(render_dir)
) )
def load_strip_from_img_seq(self, context, directory, idx: int, frame_start: int = 0): def load_strip_from_img_seq(
self, context, directory, idx: int, frame_start: int = 0
):
try: try:
# Get best preview files sequence. # Get best preview files sequence.
image_sequence = opsdata.get_best_preview_sequence(directory) image_sequence = opsdata.get_best_preview_sequence(directory)
@ -99,11 +102,11 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
# Create new image strip. # Create new image strip.
strip = context.scene.sequence_editor.sequences.new_image( strip = context.scene.sequence_editor.sequences.new_image(
name = directory.name, name=directory.name,
filepath = image_sequence[0].as_posix(), filepath=image_sequence[0].as_posix(),
channel = idx + 1, channel=idx + 1,
frame_start = frame_start, frame_start=frame_start,
fit_method = 'ORIGINAL' fit_method='ORIGINAL',
) )
# Extend strip elements with all the available frames. # Extend strip elements with all the available frames.
@ -115,7 +118,6 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
return strip return strip
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
# Clear existing strips and markers # Clear existing strips and markers
context.scene.sequence_editor_clear() context.scene.sequence_editor_clear()
@ -124,19 +126,18 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
render_dir = Path(context.scene.rr.render_dir_path) render_dir = Path(context.scene.rr.render_dir_path)
shot_version_folders_dict = self.get_shot_folder_dict( shot_version_folders_dict = self.get_shot_folder_dict(
render_dir = render_dir, render_dir=render_dir,
max_versions_per_shot = addon_prefs.versions_max_count, max_versions_per_shot=addon_prefs.versions_max_count,
) )
prev_frame_end: int = 1 prev_frame_end: int = 1
for shot_name, shot_version_folders in shot_version_folders_dict.items(): for shot_name, shot_version_folders in shot_version_folders_dict.items():
logger.info("Loading versions of shot %s", shot_name) logger.info("Loading versions of shot %s", shot_name)
imported_strips = self.import_shot_versions_as_strips( imported_strips = self.import_shot_versions_as_strips(
context, context,
shot_version_folders, shot_version_folders,
frame_start = prev_frame_end, frame_start=prev_frame_end,
shot_name = shot_name, shot_name=shot_name,
) )
if not imported_strips: if not imported_strips:
@ -174,8 +175,7 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
render_resolution_y = vars.RESOLUTION[1] render_resolution_y = vars.RESOLUTION[1]
# If Kitsu add-on is enabled, fetch the resolution from the online project # If Kitsu add-on is enabled, fetch the resolution from the online project
if ( if (
addon_prefs.enable_blender_kitsu addon_prefs.enable_blender_kitsu and prefs.is_blender_kitsu_enabled()
and prefs.is_blender_kitsu_enabled()
) and kitsu.is_active_project(): ) and kitsu.is_active_project():
# TODO: make the resolution fetching a bit more robust # TODO: make the resolution fetching a bit more robust
# Assume resolution is a string '<str:width>x<str:height>' # Assume resolution is a string '<str:width>x<str:height>'
@ -209,12 +209,11 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
return {"FINISHED"} return {"FINISHED"}
def get_shot_folder_dict( def get_shot_folder_dict(
self, self,
render_dir: str, render_dir: str,
max_versions_per_shot = 32, max_versions_per_shot=32,
) -> OrderedDict[str, List[Path]]: ) -> OrderedDict[str, List[Path]]:
shot_version_folders: List[Path] = [] shot_version_folders: List[Path] = []
# If render is sequence folder user wants to review whole sequence. # If render is sequence folder user wants to review whole sequence.
@ -237,48 +236,55 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
# Sort versions by date # Sort versions by date
for shot_name, shot_folder in shot_version_folders_dict.items(): for shot_name, shot_folder in shot_version_folders_dict.items():
shot_version_folders_dict[shot_name] = sorted(shot_folder, key=lambda dir: dir.stat().st_mtime) shot_version_folders_dict[shot_name] = sorted(shot_folder, reverse=False)
# Limit list to max number of versions # Limit list to max number of versions
shot_version_folders_dict[shot_name] = shot_version_folders_dict[shot_name][:max_versions_per_shot] shot_version_folders_dict[shot_name] = shot_version_folders_dict[shot_name][
-max_versions_per_shot:
]
# Sort shots by name # Sort shots by name
sorted_dict = OrderedDict(sorted(shot_version_folders_dict.items())) sorted_dict = OrderedDict(sorted(shot_version_folders_dict.items()))
return sorted_dict return sorted_dict
def import_shot_versions_as_strips( def import_shot_versions_as_strips(
self, self,
context: bpy.types.Context, context: bpy.types.Context,
shot_version_folders: List[Path], shot_version_folders: List[Path],
frame_start: int, frame_start: int,
shot_name: str shot_name: str,
) -> List[bpy.types.Sequence]: ) -> List[bpy.types.Sequence]:
addon_prefs = prefs.addon_prefs_get(context) addon_prefs = prefs.addon_prefs_get(context)
imported_strips: bpy.types.Sequence = [] imported_strips: bpy.types.Sequence = []
for idx, shot_folder in enumerate(shot_version_folders): shots_folder_to_add = []
if addon_prefs.shot_name_filter and addon_prefs.shot_name_filter not in shot_folder.parent.name:
# If there is a filter specified, and the shot doesn't match, skip it. if addon_prefs.shot_name_filter == "":
continue shots_folder_to_add = shot_version_folders
else:
for shot_folder in shot_version_folders:
if addon_prefs.shot_name_filter in shot_folder.parent.name:
shots_folder_to_add.append(shot_folder)
for idx, shot_folder in enumerate(shots_folder_to_add):
logger.info("Processing %s", shot_folder.name) logger.info("Processing %s", shot_folder.name)
use_video = addon_prefs.use_video and \ use_video = addon_prefs.use_video and not (
not (shot_folder != shot_version_folders[-1] and addon_prefs.use_video_latest_only) shot_folder != shot_version_folders[-1]
and addon_prefs.use_video_latest_only
)
shot_strip = self.import_shot_as_strip( shot_strip = self.import_shot_as_strip(
context, context,
frame_start = frame_start, frame_start=frame_start,
channel_idx = idx, channel_idx=idx,
shot_folder = shot_folder, shot_folder=shot_folder,
shot_name = shot_name, shot_name=shot_name,
use_video = use_video use_video=use_video,
) )
imported_strips.append(shot_strip) imported_strips.append(shot_strip)
return imported_strips return imported_strips
def import_shot_as_strip( def import_shot_as_strip(
self, self,
context: bpy.types.Context, context: bpy.types.Context,
@ -286,7 +292,7 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
channel_idx: int, channel_idx: int,
shot_folder: Path, shot_folder: Path,
shot_name: str, shot_name: str,
use_video = False, use_video=False,
) -> bpy.types.Sequence: ) -> bpy.types.Sequence:
context.scene.timeline_markers.new(shot_name, frame=frame_start) context.scene.timeline_markers.new(shot_name, frame=frame_start)
@ -305,14 +311,16 @@ class RR_OT_sqe_create_review_session(bpy.types.Operator):
logger.warning("%s found no .mp4 preview sequence", shot_folder.name) logger.warning("%s found no .mp4 preview sequence", shot_folder.name)
video_path = shot_folder video_path = shot_folder
strip = context.scene.sequence_editor.sequences.new_movie( strip = context.scene.sequence_editor.sequences.new_movie(
name = shot_folder.name, name=shot_folder.name,
filepath = video_path.as_posix(), filepath=video_path.as_posix(),
channel = channel_idx + 1, channel=channel_idx + 1,
frame_start = frame_start, frame_start=frame_start,
fit_method = 'ORIGINAL' fit_method='ORIGINAL',
) )
else: else:
strip = self.load_strip_from_img_seq(context, shot_folder, channel_idx, frame_start) strip = self.load_strip_from_img_seq(
context, shot_folder, channel_idx, frame_start
)
shot_datetime = datetime.fromtimestamp(shot_folder.stat().st_mtime) shot_datetime = datetime.fromtimestamp(shot_folder.stat().st_mtime)
time_str = shot_datetime.strftime("%B %d, %I:%M") time_str = shot_datetime.strftime("%B %d, %I:%M")
@ -342,9 +350,9 @@ class RR_OT_setup_review_workspace(bpy.types.Operator):
return [("None", "None", "None")] + cache.get_sequences_enum_list(self, context) return [("None", "None", "None")] + cache.get_sequences_enum_list(self, context)
sequence: bpy.props.EnumProperty( sequence: bpy.props.EnumProperty(
name = "Sequence", name="Sequence",
description = "Select which sequence to review", description="Select which sequence to review",
items = sequences_enum_items if prefs.is_blender_kitsu_enabled() else [] items=sequences_enum_items if prefs.is_blender_kitsu_enabled() else [],
) )
@staticmethod @staticmethod
@ -372,9 +380,11 @@ class RR_OT_setup_review_workspace(bpy.types.Operator):
area.spaces.active.show_overlays = False area.spaces.active.show_overlays = False
def invoke(self, context, _event): def invoke(self, context, _event):
if not prefs.is_blender_kitsu_enabled() or \ if (
not prefs.addon_prefs_get(context).enable_blender_kitsu or \ not prefs.is_blender_kitsu_enabled()
not kitsu.is_auth_and_project(): or not prefs.addon_prefs_get(context).enable_blender_kitsu
or not kitsu.is_auth_and_project()
):
return self.execute(context) return self.execute(context)
return context.window_manager.invoke_props_dialog(self) return context.window_manager.invoke_props_dialog(self)
@ -393,7 +403,6 @@ class RR_OT_setup_review_workspace(bpy.types.Operator):
if addon_prefs.use_video: if addon_prefs.use_video:
row.prop(addon_prefs, 'use_video_latest_only') row.prop(addon_prefs, 'use_video_latest_only')
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
scripts_path = bpy.utils.script_paths(use_user=False)[0] scripts_path = bpy.utils.script_paths(use_user=False)[0]
template_path = "/startup/bl_app_templates_system/Video_Editing/startup.blend" template_path = "/startup/bl_app_templates_system/Video_Editing/startup.blend"
@ -403,7 +412,6 @@ class RR_OT_setup_review_workspace(bpy.types.Operator):
filepath=ws_filepath.as_posix(), filepath=ws_filepath.as_posix(),
) )
# Pre-fill render directory with farm output shots directory. # Pre-fill render directory with farm output shots directory.
addon_prefs = prefs.addon_prefs_get(bpy.context) addon_prefs = prefs.addon_prefs_get(bpy.context)
context.scene.rr.render_dir = addon_prefs.farm_output_dir + "/shots" context.scene.rr.render_dir = addon_prefs.farm_output_dir + "/shots"
@ -441,9 +449,7 @@ class RR_OT_sqe_inspect_exr_sequence(bpy.types.Operator):
active_strip = context.scene.sequence_editor.active_strip active_strip = context.scene.sequence_editor.active_strip
image_editor = opsdata.get_image_editor(context) image_editor = opsdata.get_image_editor(context)
if not (active_strip if not (active_strip and active_strip.rr.is_render and image_editor):
and active_strip.rr.is_render
and image_editor):
return False return False
output_dir = opsdata.get_strip_folder(active_strip) output_dir = opsdata.get_strip_folder(active_strip)
@ -507,7 +513,6 @@ class RR_OT_sqe_clear_exr_inspect(bpy.types.Operator):
@classmethod @classmethod
def _get_image_editor(self, context: bpy.types.Context) -> Optional[bpy.types.Area]: def _get_image_editor(self, context: bpy.types.Context) -> Optional[bpy.types.Area]:
image_editor = None image_editor = None
for area in bpy.context.screen.areas: for area in bpy.context.screen.areas:
@ -551,7 +556,6 @@ class RR_OT_sqe_approve_render(bpy.types.Operator):
# Create Shot Frames path if not exists yet. # Create Shot Frames path if not exists yet.
if shot_frames_dir.exists(): if shot_frames_dir.exists():
# Delete backup if exists. # Delete backup if exists.
if shot_frames_backup_path.exists(): if shot_frames_backup_path.exists():
shutil.rmtree(shot_frames_backup_path) shutil.rmtree(shot_frames_backup_path)
@ -671,7 +675,6 @@ class RR_OT_open_path(bpy.types.Operator):
) )
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
if not self.filepath: if not self.filepath:
self.report({"ERROR"}, "Can't open empty path in explorer") self.report({"ERROR"}, "Can't open empty path in explorer")
return {"CANCELLED"} return {"CANCELLED"}
@ -714,7 +717,6 @@ class RR_OT_sqe_isolate_strip_exit(bpy.types.Operator):
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
for i in context.scene.rr.isolate_view: for i in context.scene.rr.isolate_view:
try: try:
strip = context.scene.sequence_editor.sequences[i.name] strip = context.scene.sequence_editor.sequences[i.name]
@ -742,7 +744,6 @@ class RR_OT_sqe_isolate_strip_enter(bpy.types.Operator):
return bool(active_strip) return bool(active_strip)
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
sequences = list(context.scene.sequence_editor.sequences_all) sequences = list(context.scene.sequence_editor.sequences_all)
if context.scene.rr.isolate_view.items(): if context.scene.rr.isolate_view.items():
@ -964,7 +965,6 @@ addon_keymap_items = []
def register(): def register():
for cls in classes: for cls in classes:
bpy.utils.register_class(cls) bpy.utils.register_class(cls)