[Blender_Kitsu] Publish VSE Edit as Revision on Kitsu #7
@ -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
|
||||||
|
59
blender_kitsu/gazu/edit.py
Normal file
59
blender_kitsu/gazu/edit.py
Normal 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]]
|
@ -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)
|
@ -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):
|
||||||
"""
|
"""
|
||||||
|
219
blender_kitsu/playblast/core.py
Normal file
219
blender_kitsu/playblast/core.py
Normal 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
|
@ -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):
|
||||||
|
@ -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"}
|
||||||
|
|
||||||
|
|||||||
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,
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -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 ----------.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user
Removal of the function _gen_output_path (below) results in error - #44