[Blender_Kitsu] Publish VSE Edit as Revision on Kitsu #7

Merged
Nick Alberelli merged 28 commits from :feature/upload_render_to_kitsu into master 2023-04-17 19:02:15 +02:00
8 changed files with 447 additions and 173 deletions

View File

@ -6,6 +6,7 @@ from . import asset
from . import casting from . import casting
from . import context from . import context
from . import entity from . import entity
from . import edit
from . import files from . import files
from . import project from . import project
from . import person from . import person

View File

@ -0,0 +1,59 @@
from blender_kitsu import gazu
from . import client as raw
from .sorting import sort_by_name
from .cache import cache
from .helpers import normalize_model_parameter
default = raw.default_client
@cache
def get_all_edits(relations=False, client=default):
"""
Retrieve all edit entries.
"""
params = {}
if relations:
params = {"relations": "true"}
path = "edits/all"
edits = raw.fetch_all(path, params, client=client)
return sort_by_name(edits)
@cache
def get_edit(edit_id, relations=False, client=default):
"""
Retrieve all edit entries.
"""
edit_entry = normalize_model_parameter(edit_id)
params = {}
if relations:
params = {"relations": "true"}
path = f"edits/{edit_entry['id']}"
edit_entry = raw.fetch_all(path, params, client=client)
return edit_entry
@cache
def get_all_edits_with_tasks(relations=False, client=default):
"""
Retrieve all edit entries.
"""
params = {}
if relations:
params = {"relations": "true"}
path = "edits/with-tasks"
edits_with_tasks = raw.fetch_all(path, params, client=client)
return sort_by_name(edits_with_tasks)
@cache
def get_all_previews_for_edit(edit, client=default):
"""
Args:
episode (str / dict): The episode dict or the episode ID.
Returns:
list: Shots which are children of given episode.
"""
edit = normalize_model_parameter(edit)
edit_previews = (raw.fetch_all(f"edits/{edit['id']}/preview-files", client=client))
for key in [key for key in enumerate(edit_previews.keys())]:
return edit_previews[key[1]]

View File

@ -104,3 +104,16 @@ def remove_entity(entity, force=False, client=default):
if force: if force:
params = {"force": "true"} params = {"force": "true"}
return raw.delete(path, params, client=client) return raw.delete(path, params, client=client)
def update_entity(entity, client=default):
"""
Save given shot data into the API. Metadata are fully replaced by the ones
set on given shot.
Args:
Entity (dict): The shot dict to update.
Returns:
dict: Updated entity.
"""
return raw.put(f"data/entities/{entity['id']}", entity, client=client)

View File

@ -147,6 +147,20 @@ def all_tasks_for_episode(episode, relations=False, client=default):
return sort_by_name(tasks) return sort_by_name(tasks)
@cache
def all_tasks_for_edit(edit, relations=False, client=default):
"""
Retrieve all tasks directly linked to given edit.
"""
edit = normalize_model_parameter(edit)
params = {}
if relations:
params = {"relations": "true"}
path = "edits/%s/tasks" % edit["id"]
tasks = raw.fetch_all(path, params, client=client)
return sort_by_name(tasks)
@cache @cache
def all_shot_tasks_for_sequence(sequence, relations=False, client=default): def all_shot_tasks_for_sequence(sequence, relations=False, client=default):
""" """

View File

@ -0,0 +1,219 @@
import contextlib
from blender_kitsu import (
prefs,
)
# TODO refactor so these are nest-able and re-use code
@contextlib.contextmanager
def override_render_format(self, context):
"""Overrides the render settings for playblast creation"""
rd = context.scene.render
# Format render settings.
percentage = rd.resolution_percentage
file_format = rd.image_settings.file_format
ffmpeg_constant_rate = rd.ffmpeg.constant_rate_factor
ffmpeg_codec = rd.ffmpeg.codec
ffmpeg_format = rd.ffmpeg.format
ffmpeg_audio_codec = rd.ffmpeg.audio_codec
try:
rd.resolution_percentage = 100
rd.image_settings.file_format = "FFMPEG"
rd.ffmpeg.constant_rate_factor = "HIGH"
rd.ffmpeg.codec = "H264"
rd.ffmpeg.format = "MPEG4"
rd.ffmpeg.audio_codec = "AAC"
yield
finally:
rd.resolution_percentage = percentage
rd.image_settings.file_format = file_format
rd.ffmpeg.codec = ffmpeg_codec
rd.ffmpeg.constant_rate_factor = ffmpeg_constant_rate
rd.ffmpeg.format = ffmpeg_format
rd.ffmpeg.audio_codec = ffmpeg_audio_codec
@contextlib.contextmanager
def override_render_path(self, context, render_file_path):
"""Overrides the render settings for playblast creation"""
rd = context.scene.render
# Filepath.
filepath = rd.filepath
try:
# Filepath.
rd.filepath = render_file_path
yield
finally:
# Filepath.
rd.filepath = filepath
@contextlib.contextmanager
def override_render_settings(self, context, render_file_path):
"""Overrides the render settings for playblast creation"""
addon_prefs = prefs.addon_prefs_get(context)
rd = context.scene.render
sps = context.space_data.shading
sp = context.space_data
# Get first last name for stamp note text.
session = prefs.session_get(context)
first_name = session.data.user["first_name"]
last_name = session.data.user["last_name"]
# Remember current render settings in order to restore them later.
# Filepath.
filepath = rd.filepath
# Format render settings.
percentage = rd.resolution_percentage
file_format = rd.image_settings.file_format
ffmpeg_constant_rate = rd.ffmpeg.constant_rate_factor
ffmpeg_codec = rd.ffmpeg.codec
ffmpeg_format = rd.ffmpeg.format
ffmpeg_audio_codec = rd.ffmpeg.audio_codec
# Stamp metadata settings.
metadata_input = rd.metadata_input
use_stamp_date = rd.use_stamp_date
use_stamp_time = rd.use_stamp_time
use_stamp_render_time = rd.use_stamp_render_time
use_stamp_frame = rd.use_stamp_frame
use_stamp_frame_range = rd.use_stamp_frame_range
use_stamp_memory = rd.use_stamp_memory
use_stamp_hostname = rd.use_stamp_hostname
use_stamp_camera = rd.use_stamp_camera
use_stamp_lens = rd.use_stamp_lens
use_stamp_scene = rd.use_stamp_scene
use_stamp_marker = rd.use_stamp_marker
use_stamp_marker = rd.use_stamp_marker
use_stamp_note = rd.use_stamp_note
stamp_note_text = rd.stamp_note_text
use_stamp = rd.use_stamp
stamp_font_size = rd.stamp_font_size
stamp_foreground = rd.stamp_foreground
stamp_background = rd.stamp_background
use_stamp_labels = rd.use_stamp_labels
# Space data settings.
shading_type = sps.type
shading_light = sps.light
studio_light = sps.studio_light
color_type = sps.color_type
background_type = sps.background_type
show_backface_culling = sps.show_backface_culling
show_xray = sps.show_xray
show_shadows = sps.show_shadows
show_cavity = sps.show_cavity
show_object_outline = sps.show_object_outline
show_specular_highlight = sps.show_specular_highlight
show_gizmo = sp.show_gizmo
try:
# Filepath.
rd.filepath = render_file_path
# Format render settings.
rd.resolution_percentage = 100
rd.image_settings.file_format = "FFMPEG"
rd.ffmpeg.constant_rate_factor = "HIGH"
rd.ffmpeg.codec = "H264"
rd.ffmpeg.format = "MPEG4"
rd.ffmpeg.audio_codec = "AAC"
# Stamp metadata settings.
rd.metadata_input = "SCENE"
rd.use_stamp_date = False
rd.use_stamp_time = False
rd.use_stamp_render_time = False
rd.use_stamp_frame = True
rd.use_stamp_frame_range = False
rd.use_stamp_memory = False
rd.use_stamp_hostname = False
rd.use_stamp_camera = False
rd.use_stamp_lens = True
rd.use_stamp_scene = False
rd.use_stamp_marker = False
rd.use_stamp_marker = False
rd.use_stamp_note = True
rd.stamp_note_text = f"Animator: {first_name} {last_name}"
rd.use_stamp = True
rd.stamp_font_size = 12
rd.stamp_foreground = (0.8, 0.8, 0.8, 1)
rd.stamp_background = (0, 0, 0, 0.25)
rd.use_stamp_labels = True
# Space data settings.
sps.type = "SOLID"
sps.light = "STUDIO"
sps.studio_light = "Default"
sps.color_type = "MATERIAL"
sps.background_type = "THEME"
sps.show_backface_culling = False
sps.show_xray = False
sps.show_shadows = False
sps.show_cavity = False
sps.show_object_outline = False
sps.show_specular_highlight = True
sp.show_gizmo = False
yield
finally:
# Filepath.
rd.filepath = filepath
# Return the render settings to normal.
rd.resolution_percentage = percentage
rd.image_settings.file_format = file_format
rd.ffmpeg.codec = ffmpeg_codec
rd.ffmpeg.constant_rate_factor = ffmpeg_constant_rate
rd.ffmpeg.format = ffmpeg_format
rd.ffmpeg.audio_codec = ffmpeg_audio_codec
# Stamp metadata settings.
rd.metadata_input = metadata_input
rd.use_stamp_date = use_stamp_date
rd.use_stamp_time = use_stamp_time
rd.use_stamp_render_time = use_stamp_render_time
rd.use_stamp_frame = use_stamp_frame
rd.use_stamp_frame_range = use_stamp_frame_range
rd.use_stamp_memory = use_stamp_memory
rd.use_stamp_hostname = use_stamp_hostname
rd.use_stamp_camera = use_stamp_camera
rd.use_stamp_lens = use_stamp_lens
rd.use_stamp_scene = use_stamp_scene
rd.use_stamp_marker = use_stamp_marker
rd.use_stamp_marker = use_stamp_marker
rd.use_stamp_note = use_stamp_note
rd.stamp_note_text = stamp_note_text
rd.use_stamp = use_stamp
rd.stamp_font_size = stamp_font_size
rd.stamp_foreground = stamp_foreground
rd.stamp_background = stamp_background
rd.use_stamp_labels = use_stamp_labels
# Space data settings.
sps.type = shading_type
sps.light = shading_light
sps.studio_light = studio_light
sps.color_type = color_type
sps.background_type = background_type
sps.show_backface_culling = show_backface_culling
sps.show_xray = show_xray
sps.show_shadows = show_shadows
sps.show_cavity = show_cavity
sps.show_object_outline = show_object_outline
sps.show_specular_highlight = show_specular_highlight
sp.show_gizmo = show_gizmo

View File

@ -18,7 +18,6 @@
# #
# (c) 2023, Blender Foundation # (c) 2023, Blender Foundation
import contextlib
import webbrowser import webbrowser
from pathlib import Path from pathlib import Path
from typing import Dict, List, Set, Optional, Tuple, Any from typing import Dict, List, Set, Optional, Tuple, Any
@ -39,7 +38,7 @@ from blender_kitsu.types import (
TaskStatus, TaskStatus,
TaskType, TaskType,
) )
from blender_kitsu.playblast.core import override_render_settings
from blender_kitsu.playblast import opsdata from blender_kitsu.playblast import opsdata
logger = LoggerFactory.getLogger() logger = LoggerFactory.getLogger()
@ -92,7 +91,7 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
context.window_manager.progress_update(0) context.window_manager.progress_update(0)
# Render and save playblast # Render and save playblast
with self.override_render_settings(context): with override_render_settings(self, context, context.scene.kitsu.playblast_file):
# Get output path. # Get output path.
output_path = Path(context.scene.kitsu.playblast_file) output_path = Path(context.scene.kitsu.playblast_file)
@ -264,169 +263,6 @@ class KITSU_OT_playblast_create(bpy.types.Operator):
url = f"{host_url}/productions/{cache.project_active_get().id}/shots?search={cache.shot_active_get().name}" url = f"{host_url}/productions/{cache.project_active_get().id}/shots?search={cache.shot_active_get().name}"
webbrowser.open(url) webbrowser.open(url)
@contextlib.contextmanager
def override_render_settings(self, context):
"""Overrides the render settings for playblast creation"""
addon_prefs = prefs.addon_prefs_get(context)
rd = context.scene.render
sps = context.space_data.shading
sp = context.space_data
# Get first last name for stamp note text.
session = prefs.session_get(context)
first_name = session.data.user["first_name"]
last_name = session.data.user["last_name"]
# Remember current render settings in order to restore them later.
# Filepath.
filepath = rd.filepath
# Format render settings.
percentage = rd.resolution_percentage
file_format = rd.image_settings.file_format
ffmpeg_constant_rate = rd.ffmpeg.constant_rate_factor
ffmpeg_codec = rd.ffmpeg.codec
ffmpeg_format = rd.ffmpeg.format
ffmpeg_audio_codec = rd.ffmpeg.audio_codec
# Stamp metadata settings.
metadata_input = rd.metadata_input
use_stamp_date = rd.use_stamp_date
use_stamp_time = rd.use_stamp_time
use_stamp_render_time = rd.use_stamp_render_time
use_stamp_frame = rd.use_stamp_frame
use_stamp_frame_range = rd.use_stamp_frame_range
use_stamp_memory = rd.use_stamp_memory
use_stamp_hostname = rd.use_stamp_hostname
use_stamp_camera = rd.use_stamp_camera
use_stamp_lens = rd.use_stamp_lens
use_stamp_scene = rd.use_stamp_scene
use_stamp_marker = rd.use_stamp_marker
use_stamp_marker = rd.use_stamp_marker
use_stamp_note = rd.use_stamp_note
stamp_note_text = rd.stamp_note_text
use_stamp = rd.use_stamp
stamp_font_size = rd.stamp_font_size
stamp_foreground = rd.stamp_foreground
stamp_background = rd.stamp_background
use_stamp_labels = rd.use_stamp_labels
# Space data settings.
shading_type = sps.type
shading_light = sps.light
studio_light = sps.studio_light
color_type = sps.color_type
background_type = sps.background_type
show_backface_culling = sps.show_backface_culling
show_xray = sps.show_xray
show_shadows = sps.show_shadows
show_cavity = sps.show_cavity
show_object_outline = sps.show_object_outline
show_specular_highlight = sps.show_specular_highlight
show_gizmo = sp.show_gizmo
try:
# Filepath.
rd.filepath = context.scene.kitsu.playblast_file
# Format render settings.
rd.resolution_percentage = 100
rd.image_settings.file_format = "FFMPEG"
rd.ffmpeg.constant_rate_factor = "HIGH"
rd.ffmpeg.codec = "H264"
rd.ffmpeg.format = "MPEG4"
rd.ffmpeg.audio_codec = "AAC"
# Stamp metadata settings.
rd.metadata_input = "SCENE"
rd.use_stamp_date = False
rd.use_stamp_time = False
rd.use_stamp_render_time = False
rd.use_stamp_frame = True
rd.use_stamp_frame_range = False
rd.use_stamp_memory = False
rd.use_stamp_hostname = False
rd.use_stamp_camera = False
rd.use_stamp_lens = True
rd.use_stamp_scene = False
rd.use_stamp_marker = False
rd.use_stamp_marker = False
rd.use_stamp_note = True
rd.stamp_note_text = f"Animator: {first_name} {last_name}"
rd.use_stamp = True
rd.stamp_font_size = 12
rd.stamp_foreground = (0.8, 0.8, 0.8, 1)
rd.stamp_background = (0, 0, 0, 0.25)
rd.use_stamp_labels = True
# Space data settings.
sps.type = "SOLID"
sps.light = "STUDIO"
sps.studio_light = "Default"
sps.color_type = "MATERIAL"
sps.background_type = "THEME"
sps.show_backface_culling = False
sps.show_xray = False
sps.show_shadows = False
sps.show_cavity = False
sps.show_object_outline = False
sps.show_specular_highlight = True
sp.show_gizmo = False
yield
finally:
# Filepath.
rd.filepath = filepath
# Return the render settings to normal.
rd.resolution_percentage = percentage
rd.image_settings.file_format = file_format
rd.ffmpeg.codec = ffmpeg_codec
rd.ffmpeg.constant_rate_factor = ffmpeg_constant_rate
rd.ffmpeg.format = ffmpeg_format
rd.ffmpeg.audio_codec = ffmpeg_audio_codec
# Stamp metadata settings.
rd.metadata_input = metadata_input
rd.use_stamp_date = use_stamp_date
rd.use_stamp_time = use_stamp_time
rd.use_stamp_render_time = use_stamp_render_time
rd.use_stamp_frame = use_stamp_frame
rd.use_stamp_frame_range = use_stamp_frame_range
rd.use_stamp_memory = use_stamp_memory
rd.use_stamp_hostname = use_stamp_hostname
rd.use_stamp_camera = use_stamp_camera
rd.use_stamp_lens = use_stamp_lens
rd.use_stamp_scene = use_stamp_scene
rd.use_stamp_marker = use_stamp_marker
rd.use_stamp_marker = use_stamp_marker
rd.use_stamp_note = use_stamp_note
rd.stamp_note_text = stamp_note_text
rd.use_stamp = use_stamp
rd.stamp_font_size = stamp_font_size
rd.stamp_foreground = stamp_foreground
rd.stamp_background = stamp_background
rd.use_stamp_labels = use_stamp_labels
# Space data settings.
sps.type = shading_type
sps.light = shading_light
sps.studio_light = studio_light
sps.color_type = color_type
sps.background_type = background_type
sps.show_backface_culling = show_backface_culling
sps.show_xray = show_xray
sps.show_shadows = show_shadows
sps.show_cavity = show_cavity
sps.show_object_outline = show_object_outline
sps.show_specular_highlight = show_specular_highlight
sp.show_gizmo = show_gizmo
class KITSU_OT_playblast_set_version(bpy.types.Operator): class KITSU_OT_playblast_set_version(bpy.types.Operator):

View File

@ -24,7 +24,7 @@ import colorsys
import random import random
from pathlib import Path from pathlib import Path
from typing import Dict, List, Set, Optional, Tuple, Any from typing import Dict, List, Set, Optional, Tuple, Any
import datetime
import bpy import bpy
from blender_kitsu import gazu, cache, util, prefs, bkglobals from blender_kitsu import gazu, cache, util, prefs, bkglobals
@ -40,6 +40,8 @@ from blender_kitsu.types import (
Task, Task,
) )
from blender_kitsu.playblast.core import override_render_path, override_render_format
logger = LoggerFactory.getLogger() logger = LoggerFactory.getLogger()
@ -307,7 +309,6 @@ 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"
@ -1404,11 +1405,7 @@ class KITSU_OT_sqe_push_render(bpy.types.Operator):
logger.info("-END- Pushing Sequence Editor Render") logger.info("-END- Pushing Sequence Editor Render")
return {"FINISHED"} return {"FINISHED"}

Removal of the function _gen_output_path (below) results in error - #44

Removal of the function _gen_output_path (below) results in error - #44
def _gen_output_path(self, strip: bpy.types.Sequence, task_type: TaskType) -> Path:
addon_prefs = prefs.addon_prefs_get(bpy.context)
folder_name = addon_prefs.sqe_render_dir
file_name = f"{strip.kitsu.shot_id}_{strip.kitsu.shot_name}.{(task_type.name).lower()}.mp4"
return Path(folder_name).absolute().joinpath(file_name)

Removal of this function results in error - studio/blender-studio-pipeline#44

Removal of this function results in error - https://projects.blender.org/studio/blender-studio-pipeline/issues/44
@contextlib.contextmanager @contextlib.contextmanager
def override_render_settings(self, context, thumbnail_width=256): def override_render_settings(self, context, thumbnail_width=256):
@ -2399,6 +2396,131 @@ 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):
if get_entity_data(entity, key) is not None:
entity['data'][key] = value
return entity
def get_entity_data(entity, key: str):
if entity.get("data").get(key) is not None:
return entity.get("data").get(key)
def get_dict_len(items:dict):
try:
return len(items)
except TypeError:
return None
def set_revision_int(prev_rev=None):
if prev_rev is None:
return 1
return prev_rev+1
class KITSU_OT_vse_publish_edit_revision(bpy.types.Operator):
bl_idname = "kitsu.vse_publish_edit_revision"
bl_label = "Render and 'Publish as Revision'"
bl_description = "Renders current VSE Edit as .mp4 and publishes as revision on 'Edit Task'"
def get_edit_entry_items(self: Any, context: bpy.types.Context) -> List[Tuple[str, str, str]]:
sorted_edits = []
active_project = cache.project_active_get()
for edit in gazu.edit.get_all_edits_with_tasks():
if (edit["project_id"] == active_project.id) and not edit['canceled']:
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]
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)
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")
edit_entry: bpy.props.EnumProperty(name="Edit", items=get_edit_entry_items)
task: bpy.props.EnumProperty(name="Edit", items=get_edit_task_items)
render_dir: bpy.props.StringProperty(
name="Folder",
subtype="DIR_PATH",
)
use_frame_start: bpy.props.BoolProperty(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
def poll(cls, context: bpy.types.Context) -> bool:
return bool(
prefs.session_auth(context)
and cache.project_active_get()
)
def invoke(self, context, event):
# Remove file name if set in render.filepath
dir_path = bpy.path.abspath(context.scene.render.filepath)
if not os.path.isdir(Path(dir_path)):
dir_path = Path(dir_path).parent
self.render_dir = str(dir_path)
#'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')
self.frame_start = server_frame_start
self.use_frame_start = bool(server_frame_start is not None)
return context.window_manager.invoke_props_dialog(self)
def draw(self, context: bpy.types.Context) -> None:
layout = self.layout
layout.prop(self, "edit_entry")
if len(self.get_edit_task_items(context)) >= 2:
layout.prop(self, "task")
layout.prop(self, "comment")
layout.prop(self, "render_dir")
# Only set `frame_start` if exists on current project
if self.use_frame_start:
layout.prop(self, "frame_start")
def execute(self, context: bpy.types.Context) -> Set[str]:
if self.task == "":
self.report({"ERROR"}, "Selected edit doesn't have any task associated with it .")
return {"CANCELLED"}
active_project = cache.project_active_get()
existing_previews = gazu.edit.get_all_previews_for_edit(self.edit_entry)
len_previews = get_dict_len(existing_previews)
revision = set_revision_int(len_previews)
# Build render_path
render_dir = bpy.path.abspath(self.render_dir)
if not os.path.isdir(Path(render_dir)):
self.report(
{"ERROR"},
f"Render path is not set to a directory. '{self.render_dir}'"
)
return {"CANCELLED"}
edit_entry = gazu.edit.get_edit(self.edit_entry)
render_name = f"{active_project.name}_{edit_entry.get('name')}_v{revision}.mp4"
render_path = Path(render_dir).joinpath(render_name)
# Render Sequence to .mp4
with override_render_path(self, context, render_path.as_posix()):
with override_render_format(self, context):
bpy.ops.render.opengl(animation=True, sequencer=True)
# Create comment with video
task_entity = gazu.task.get_task(self.task)
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)
# Update edit_entry's frame_start if 'frame_start' is found on server
if self.use_frame_start:
edit_entity_update = set_entity_data(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}'"
)
return {"FINISHED"}
# ---------REGISTER ----------. # ---------REGISTER ----------.
@ -2429,6 +2551,8 @@ classes = [
KITSU_OT_sqe_scan_for_media_updates, KITSU_OT_sqe_scan_for_media_updates,
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,
] ]

View File

@ -735,6 +735,14 @@ class KITSU_PT_sqe_general_tools(bpy.types.Panel):
KITSU_OT_sqe_change_strip_source.bl_idname, text="", icon="FILE_PARENT" KITSU_OT_sqe_change_strip_source.bl_idname, text="", icon="FILE_PARENT"
).go_latest = True ).go_latest = True
# Create box.
layout = self.layout
box = layout.box()
box.label(text="Edit Tasks", icon="SEQ_SEQUENCER")
# Scan for outdated media and reset operator.
row = box.row(align=True)
row.operator("kitsu.vse_publish_edit_revision")
# ---------REGISTER ----------. # ---------REGISTER ----------.