Blender Kitsu: Set Custom Thumbnail during Playblast #77

Merged
Nick Alberelli merged 12 commits from feature/custom-playblast-thumbnails into main 2023-06-15 21:26:54 +02:00
3 changed files with 46 additions and 14 deletions

View File

@ -896,19 +896,21 @@ def add_preview(
) )
def set_main_preview(preview_file, client=default): def set_main_preview(preview_file, frame_number, client=default):
""" """
Set given preview as thumbnail of given entity. Set given preview as thumbnail of given entity.
Args: Args:
preview_file (str / dict): The preview file dict or ID. preview_file (str / dict): The preview file dict or ID.
frame_number (int): Frame of preview video to set as main preview
Returns: Returns:
dict: Created preview file model. dict: Created preview file model.
""" """
data = {"frame_number": frame_number} if frame_number > 1 else {}
preview_file = normalize_model_parameter(preview_file) preview_file = normalize_model_parameter(preview_file)
path = "actions/preview-files/%s/set-main-preview" % preview_file["id"] path = "actions/preview-files/%s/set-main-preview" % preview_file["id"]
return raw.put(path, {}, client=client) return raw.put(path, data, client=client)
@cache @cache

View File

@ -38,7 +38,10 @@ from blender_kitsu.types import (
TaskStatus, TaskStatus,
TaskType, TaskType,
) )
from blender_kitsu.playblast.core import playblast_with_shading_settings, playblast_user_shading_settings from blender_kitsu.playblast.core import (
playblast_with_shading_settings,
playblast_user_shading_settings,
)
from blender_kitsu.playblast import opsdata from blender_kitsu.playblast import opsdata
logger = LoggerFactory.getLogger() logger = LoggerFactory.getLogger()
@ -64,7 +67,14 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
task_status: bpy.props.EnumProperty(items=cache.get_all_task_statuses_enum) # type: ignore task_status: bpy.props.EnumProperty(items=cache.get_all_task_statuses_enum) # type: ignore
use_user_shading: bpy.props.BoolProperty( use_user_shading: bpy.props.BoolProperty(
name="Use Current Viewport Shading", default=True) name="Use Current Viewport Shading", default=True
)
thumbnail_frame: bpy.props.IntProperty(
name="Thumbnail Frame",
description="Frame to use as the thumbnail on Kitsu",
min=0,
)
thumbnail_frame_final: bpy.props.IntProperty(name="Thumbnail Frame Final")
@classmethod @classmethod
def poll(cls, context: bpy.types.Context) -> bool: def poll(cls, context: bpy.types.Context) -> bool:
@ -76,13 +86,25 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
) )
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)
if not self.task_status: if not self.task_status:
self.report({"ERROR"}, "Failed to create playblast. Missing task status") self.report({"ERROR"}, "Failed to create playblast. Missing task status")
return {"CANCELLED"} return {"CANCELLED"}
# Playblast file always starts at frame 0, account for this in thumbnail frame selection
self.thumbnail_frame_final = self.thumbnail_frame - context.scene.frame_start
# Ensure thumbnail frame is not outside of frame range
if self.thumbnail_frame_final not in range(
0, (context.scene.frame_end - context.scene.frame_start) + 1
):
self.report(
{"ERROR"},
f"Thumbnail frame '{self.thumbnail_frame}' is outside of frame range ",
)
return {"CANCELLED"}
shot_active = cache.shot_active_get() shot_active = cache.shot_active_get()
# Save playblast task status id for next time. # Save playblast task status id for next time.
@ -96,12 +118,14 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
# Render and save playblast # Render and save playblast
if self.use_user_shading: if self.use_user_shading:
output_path = playblast_user_shading_settings( output_path = playblast_user_shading_settings(
self, context, context.scene.kitsu.playblast_file) self, context, context.scene.kitsu.playblast_file
)
else: else:
# Get output path. # Get output path.
output_path = playblast_with_shading_settings( output_path = playblast_with_shading_settings(
self, context, context.scene.kitsu.playblast_file) self, context, context.scene.kitsu.playblast_file
)
context.window_manager.progress_update(1) context.window_manager.progress_update(1)
@ -152,7 +176,9 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
# Setup video sequence editor space. # Setup video sequence editor space.
if "Video Editing" not in [ws.name for ws in bpy.data.workspaces]: if "Video Editing" not in [ws.name for ws in bpy.data.workspaces]:
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"
)
ws_filepath = Path(scripts_path + template_path) ws_filepath = Path(scripts_path + template_path)
bpy.ops.workspace.append_activate( bpy.ops.workspace.append_activate(
idname="Video Editing", idname="Video Editing",
@ -191,6 +217,7 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
def invoke(self, context, event): def invoke(self, context, event):
# Initialize comment and playblast task status variable. # Initialize comment and playblast task status variable.
self.comment = "" self.comment = ""
self.thumbnail_frame = context.scene.frame_current
prev_task_status_id = context.scene.kitsu.playblast_task_status_id prev_task_status_id = context.scene.kitsu.playblast_task_status_id
if prev_task_status_id: if prev_task_status_id:
@ -211,6 +238,7 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
row.prop(self, "comment") row.prop(self, "comment")
row = layout.row(align=True) row = layout.row(align=True)
row.prop(self, "use_user_shading") row.prop(self, "use_user_shading")
row.prop(self, "thumbnail_frame")
def _upload_playblast(self, context: bpy.types.Context, filepath: Path) -> None: def _upload_playblast(self, context: bpy.types.Context, filepath: Path) -> None:
# Get shot. # Get shot.
@ -241,7 +269,11 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
) )
# Add_preview_to_comment # Add_preview_to_comment
task.add_preview_to_comment(comment, filepath.as_posix()) task.add_preview_to_comment(
comment,
filepath.as_posix(),
self.thumbnail_frame_final,
)
# Preview.set_main_preview() # Preview.set_main_preview()
logger.info(f"Uploaded playblast for shot: {shot.name} under: {task_type.name}") logger.info(f"Uploaded playblast for shot: {shot.name} under: {task_type.name}")
@ -267,7 +299,6 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
webbrowser.open(url) webbrowser.open(url)
class KITSU_OT_playblast_set_version(bpy.types.Operator): class KITSU_OT_playblast_set_version(bpy.types.Operator):
bl_idname = "kitsu.anim_set_playblast_version" bl_idname = "kitsu.anim_set_playblast_version"
bl_label = "Version" bl_label = "Version"
@ -365,7 +396,6 @@ class KITSU_OT_playblast_increment_playblast_version(bpy.types.Operator):
return True return True
def execute(self, context: bpy.types.Context) -> Set[str]: def execute(self, context: bpy.types.Context) -> Set[str]:
# Incremenet version. # Incremenet version.
version = opsdata.add_playblast_version_increment(context) version = opsdata.add_playblast_version_increment(context)
@ -465,7 +495,6 @@ def register():
def unregister(): def unregister():
# Clear handlers. # Clear handlers.
bpy.app.handlers.load_post.remove(load_post_handler_check_frame_range) bpy.app.handlers.load_post.remove(load_post_handler_check_frame_range)
bpy.app.handlers.load_post.remove(load_post_handler_init_version_model) bpy.app.handlers.load_post.remove(load_post_handler_init_version_model)

View File

@ -874,11 +874,12 @@ class Task(Entity):
return comment_obj return comment_obj
def add_preview_to_comment( def add_preview_to_comment(
self, comment: Comment, preview_file_path: str self, comment: Comment, preview_file_path: str,
) -> Preview: frame_number:int) -> Preview:
preview_dict = gazu.task.add_preview( preview_dict = gazu.task.add_preview(
asdict(self), asdict(comment), preview_file_path asdict(self), asdict(comment), preview_file_path
) )
gazu.task.set_main_preview(preview_dict["id"], frame_number)
return Preview.from_dict(preview_dict) return Preview.from_dict(preview_dict)
def __bool__(self) -> bool: def __bool__(self) -> bool: