export background

pull/5/head
“christopheseux” 2023-05-19 11:51:05 +02:00
parent 48dddb1905
commit beb85721a9
10 changed files with 416 additions and 120 deletions

View File

@ -36,8 +36,8 @@ if 'bpy' in locals():
import bpy import bpy
def register(): def register():
print('Register update script handler')
bpy.app.handlers.frame_change_post.append(update_text_strips) bpy.app.handlers.frame_change_post.append(update_text_strips)
bpy.app.handlers.render_pre.append(update_text_strips)
if bpy.app.background: if bpy.app.background:
return return
@ -51,6 +51,7 @@ def register():
def unregister(): def unregister():
bpy.app.handlers.frame_change_post.remove(update_text_strips) bpy.app.handlers.frame_change_post.remove(update_text_strips)
bpy.app.handlers.render_pre.remove(update_text_strips)
try: try:
bpy.utils.previews.remove(ASSET_PREVIEWS) bpy.utils.previews.remove(ASSET_PREVIEWS)

View File

@ -2,9 +2,19 @@
""" """
Generic Blender functions Generic Blender functions
""" """
import os
from pathlib import Path
import subprocess
import json
from textwrap import dedent
import bpy import bpy
def abspath(path):
path = os.path.abspath(bpy.path.abspath(path))
return Path(path)
def get_scene_settings(): def get_scene_settings():
return bpy.context.scene.vsetb_settings return bpy.context.scene.vsetb_settings
@ -17,7 +27,27 @@ def get_strip_settings():
return strip.vsetb_strip_settings return strip.vsetb_strip_settings
def get_bl_cmd(blender=None, background=False, focus=True, blendfile=None, script=None, **kargs): def norm_arg(arg_name):
return "--" + arg_name.replace(' ', '-')
def norm_value(value):
if isinstance(value, (tuple, list)):
values = []
for v in value:
if not isinstance(v, str):
v = json.dumps(v)
values.append(v)
return values
if isinstance(value, Path):
return str(value)
if not isinstance(value, str):
value = json.dumps(value)
return value
def get_bl_cmd(blender=None, background=False, focus=True, blendfile=None, script=None, output=None, **kargs):
cmd = [str(blender)] if blender else [bpy.app.binary_path] cmd = [str(blender)] if blender else [bpy.app.binary_path]
if background: if background:
@ -31,6 +61,9 @@ def get_bl_cmd(blender=None, background=False, focus=True, blendfile=None, scrip
if blendfile: if blendfile:
cmd += [str(blendfile)] cmd += [str(blendfile)]
if output:
cmd += ['-o', str(output)]
if script: if script:
cmd += ['--python', str(script)] cmd += ['--python', str(script)]
@ -49,6 +82,28 @@ def get_bl_cmd(blender=None, background=False, focus=True, blendfile=None, scrip
return cmd return cmd
def background_render(output=None):
#bpy.context.scene.render.filepath = '{output}'
script_code = dedent(f"""
import bpy
bpy.context.scene.render.filepath = '{str(output)}'
bpy.ops.render.render(animation=True)
bpy.ops.wm.quit_blender()
""")
tmp_blend = Path(bpy.app.tempdir) / Path(bpy.data.filepath).name
bpy.ops.wm.save_as_mainfile(filepath=str(tmp_blend))
script_path = Path(bpy.app.tempdir) / 'render_blender_background.py'
script_path.write_text(script_code)
cmd = get_bl_cmd(blendfile=tmp_blend, script=script_path, background=True)
print('Background Render...')
print(cmd)
subprocess.Popen(cmd)
def get_addon_prefs(): def get_addon_prefs():
addon_name = __package__.split('.')[0] addon_name = __package__.split('.')[0]
return bpy.context.preferences.addons[addon_name].preferences return bpy.context.preferences.addons[addon_name].preferences

View File

@ -1,13 +1,13 @@
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
from vse_toolbox.operators import (addon, casting, imports, render, sequencer, from vse_toolbox.operators import (addon, casting, imports, exports, sequencer,
spreadsheet, tracker) spreadsheet, tracker)
modules = ( modules = (
addon, addon,
casting, casting,
imports, imports,
render, exports,
sequencer, sequencer,
spreadsheet, spreadsheet,
tracker tracker

View File

@ -2,7 +2,7 @@
import json import json
import bpy import bpy
from bpy.types import PropertyGroup, Operator from bpy.types import Context, Event, PropertyGroup, Operator
from bpy.props import (CollectionProperty, EnumProperty, StringProperty) from bpy.props import (CollectionProperty, EnumProperty, StringProperty)
from vse_toolbox.constants import CASTING_BUFFER from vse_toolbox.constants import CASTING_BUFFER
@ -249,15 +249,27 @@ class VSETB_OT_copy_casting(Operator):
class VSETB_OT_paste_casting(Operator): class VSETB_OT_paste_casting(Operator):
bl_idname = "vse_toolbox.paste_casting" bl_idname = "vse_toolbox.paste_casting"
bl_label = "Paste Casting" bl_label = "Paste Casting"
bl_description = "Paste Casting to active strip" bl_description = "Paste Casting to active strip (ctrl|shift: Add, alt:Remove)"
bl_options = {"REGISTER", "UNDO"} bl_options = {"REGISTER", "UNDO"}
mode : EnumProperty(items=[(m, m.title(), '') for m in ('REPLACE', 'ADD', 'REMOVE')])
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
active_strip = context.scene.sequence_editor.active_strip active_strip = context.scene.sequence_editor.active_strip
if active_strip: if active_strip:
return True return True
def invoke(self, context, event):
self.mode = 'REPLACE'
if event.ctrl or event.shift:
self.mode = 'ADD'
elif event.alt:
self.mode = 'REMOVE'
return self.execute(context)
def execute(self, context): def execute(self, context):
scn = context.scene scn = context.scene
strip_settings = get_strip_settings() strip_settings = get_strip_settings()
@ -267,19 +279,33 @@ class VSETB_OT_paste_casting(Operator):
return {"CANCELLED"} return {"CANCELLED"}
casting_datas = json.loads(CASTING_BUFFER.read_text()) casting_datas = json.loads(CASTING_BUFFER.read_text())
casting_ids = set(c['id'] for c in casting_datas)
for strip in context.selected_sequences: for strip in context.selected_sequences:
strip_settings = strip.vsetb_strip_settings strip_settings = strip.vsetb_strip_settings
strip.vsetb_strip_settings.casting.clear()
if self.mode == 'REPLACE':
strip.vsetb_strip_settings.casting.clear()
for casting_data in casting_datas: for casting_data in casting_datas:
if self.mode == 'REMOVE':
item = strip.vsetb_strip_settings.casting.add()
for asset_casting in strip_settings.casting:
index = list(strip_settings.casting).index(asset_casting)
if asset_casting.id in casting_ids:
strip_settings.casting.remove(index)
item.name = casting_data['name'] if strip_settings.casting_index != 0:
item.id = casting_data['id'] strip_settings.casting_index -= 1
item['_name'] = casting_data['_name']
strip_settings.casting.update() else:
item = strip.vsetb_strip_settings.casting.add()
item.name = casting_data['name']
item.id = casting_data['id']
item['_name'] = casting_data['_name']
strip_settings.casting.update()
return {"FINISHED"} return {"FINISHED"}

183
operators/exports.py Normal file
View File

@ -0,0 +1,183 @@
import time
import re
from pathlib import Path
import os
import bpy
from bpy.types import Operator
from bpy.props import BoolProperty
from vse_toolbox.sequencer_utils import (get_strips, render_strip)
from vse_toolbox.bl_utils import (get_scene_settings, background_render)
from vse_toolbox.file_utils import install_module
class VSETB_OT_render(Operator):
bl_idname = "vse_toolbox.strips_render"
bl_label = "Render Shots Strips"
bl_description = "Render Shots Strips"
bl_options = {"REGISTER", "UNDO"}
#selected_only : BoolProperty(name="Selected Only", default=False)
@classmethod
def poll(cls, context):
settings = get_scene_settings()
return settings.active_project
def invoke(self, context, event):
scn = context.scene
settings = get_scene_settings()
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
scn = context.scene
settings = get_scene_settings()
layout = self.layout
col = layout.column()
#col.use_property_split = True
#col.use_property_decorate = False
col.prop(settings.active_project, "render_single_file")
row = col.row()
row.enabled = settings.active_project.render_single_file
row.prop(settings.active_project, "render_template")
col.separator()
col.prop(settings.active_project, "render_per_strip")
row = col.row()
row.enabled = settings.active_project.render_per_strip
row.prop(settings.active_project, "render_strip_template")
#col.prop(settings, 'channel', text='Channel')
#col.prop(self, 'selected_only')
def execute(self, context):
scn = context.scene
settings = get_scene_settings()
project = settings.active_project
format_data = {**settings.format_data, **project.format_data}
start_time = time.perf_counter()
if project.render_single_file:
render_path = project.render_template.format(**format_data)
background_render(output=render_path)
if project.render_per_strip:
for strip in get_strips(channel='Shots', selected_only=True):
strip_settings = strip.vsetb_strip_settings
strip_data = {**format_data, **strip_settings.format_data}
strip_render_path = project.render_strip_template.format(**strip_data)
render_strip(strip, strip_render_path)
self.report({"INFO"}, f'Strips rendered in {time.perf_counter()-start_time} seconds')
return {"FINISHED"}
class VSETB_OT_export_edl(Operator):
bl_idname = "vse_toolbox.export_edl"
bl_label = "Export Edl"
bl_description = "Export Edl"
bl_options = {"REGISTER", "UNDO"}
#selected_only : BoolProperty(name="Selected Only", default=False)
@classmethod
def poll(cls, context):
settings = get_scene_settings()
return settings.active_project
def invoke(self, context, event):
scn = context.scene
settings = get_scene_settings()
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
scn = context.scene
settings = get_scene_settings()
layout = self.layout
col = layout.column()
col.use_property_split = True
col.use_property_decorate = False
#col.prop(settings, 'channel', text='Channel')
#col.prop(self, 'selected_only')
col.prop(settings.active_project, "export_edl_template")
def execute(self, context):
opentimelineio = install_module('opentimelineio')
from opentimelineio.schema import (Clip, Timeline, Track, ExternalReference)
from opentimelineio.opentime import (RationalTime, TimeRange)
start_time = time.perf_counter()
scn = context.scene
settings = get_scene_settings()
fps = scn.render.fps
project = settings.active_project
format_data = {**settings.format_data, **project.format_data}
output_edl = project.export_edl_template.format(**format_data)
output_edl = os.path.abspath(bpy.path.abspath(output_edl))
output_edl = Path(output_edl)
timeline = Timeline(output_edl.stem)
track = Track(f"Track 1")
track.kind = "Video"
timeline.tracks.append(track)
for strip in get_strips(channel='Shots', selected_only=False):
strip_data = {**format_data, **strip.vsetb_strip_settings.format_data}
strip_render_path = project.render_strip_template.format(**strip_data)
clip = Clip(Path(strip_render_path).name)
clip.metadata.setdefault("cmx_3600", {})
clip.metadata['cmx_3600']['reel'] = strip.name
#clip.metadata['cmx_3600']['flags'] = 'IS_CLIP'
#clip.media_reference = ExternalReference(f'//render/{strip.name}.mov')
#clip.media_reference.name = strip.name
#clip.available_range = TimeRange(RationalTime(0, fps), RationalTime(strip.frame_duration, fps))
clip.source_range = TimeRange(RationalTime(strip.frame_offset_start, fps), RationalTime(strip.frame_final_duration, fps))
track.append(clip)
output_edl.parent.mkdir(exist_ok=True, parents=True)
edl = opentimelineio.adapters.write_to_string(timeline, 'cmx_3600')
output_edl.write_text(edl)
#opentimelineio.adapters.write_to_file(timeline, str(output_edl), 'cmx_3600')
self.report({"INFO"}, f'Edl Exported in {time.perf_counter()-start_time} seconds')
return {"FINISHED"}
classes = (
VSETB_OT_render,
VSETB_OT_export_edl
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)

View File

@ -1,70 +0,0 @@
import time
import bpy
from bpy.types import Operator
from vse_toolbox.sequencer_utils import (get_strips, render_strips)
from vse_toolbox.bl_utils import get_scene_settings
class VSETB_OT_render(Operator):
bl_idname = "vse_toolbox.strips_render"
bl_label = "Render Shots Strips"
bl_description = "Render Shots Strips"
bl_options = {"REGISTER", "UNDO"}
#selected_only : BoolProperty(name="Selected Only", default=False)
@classmethod
def poll(cls, context):
settings = get_scene_settings()
return settings.active_project
def invoke(self, context, event):
scn = context.scene
settings = get_scene_settings()
return context.window_manager.invoke_props_dialog(self)
def draw(self, context):
scn = context.scene
settings = get_scene_settings()
layout = self.layout
col = layout.column()
col.use_property_split = True
col.use_property_decorate = False
#col.prop(settings, 'channel', text='Channel')
#col.prop(self, 'selected_only')
col.prop(settings.active_project, "render_template")
def execute(self, context):
scn = context.scene
settings = get_scene_settings()
strips = get_strips(channel='Shots', selected_only=True)
start_time = time.perf_counter()
render_strips(strips, settings.active_project.render_template)
self.report({"INFO"}, f'Strips rendered in {time.perf_counter()-start_time} seconds')
return {"FINISHED"}
classes = (
VSETB_OT_render,
)
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)

View File

@ -171,6 +171,40 @@ class VSETB_OT_spreadsheet_from_clipboard(Operator):
return {"FINISHED"} return {"FINISHED"}
class VSETB_OT_spreadsheet_to_clipboard(Operator):
bl_idname = "vse_toolbox.spreadsheet_to_clipboard"
bl_label = "Copy Spreadsheet to clipboard"
bl_description = "Copy Spreadsheet to clipboard"
bl_options = {"REGISTER", "UNDO"}
def execute(self, context):
scn = context.scene
project = get_scene_settings().active_project
import_cells = project.spreadsheet_import.cells
import_cells.clear()
SPREADSHEET.clear()
spreadsheet = context.window_manager.clipboard
cell_types = project.get_cell_types()
rows = list(csv.reader(StringIO(spreadsheet), delimiter='\t'))
for cell_name in rows[0]:
if not cell_name:
continue
cell = import_cells.add()
cell.name = cell_name
cell.import_name = max(cell_types.keys(), key=lambda x: fuzzy_match(cell_name, x))
cell.enabled = True
project.spreadsheet_import.use_custom_cells = True
SPREADSHEET.extend(rows)
return {"FINISHED"}
class VSETB_OT_import_spreadsheet(Operator): class VSETB_OT_import_spreadsheet(Operator):
bl_idname = "vse_toolbox.import_spreadsheet" bl_idname = "vse_toolbox.import_spreadsheet"
bl_label = "Import Spreadsheet" bl_label = "Import Spreadsheet"
@ -368,13 +402,7 @@ class VSETB_OT_import_spreadsheet(Operator):
strip_settings.casting.update() strip_settings.casting.update()
else: else:
self.report({'WARNING'}, f'Asset {asset_name} not found in Project') self.report({'WARNING'}, f'Asset {asset_name} not found in Project')
return {"FINISHED"} return {"FINISHED"}
@ -446,12 +474,13 @@ class VSETB_OT_export_spreadsheet(Operator):
row.prop(spreadsheet, 'show_settings', text='', icon='PREFERENCES') row.prop(spreadsheet, 'show_settings', text='', icon='PREFERENCES')
if spreadsheet.show_settings: if spreadsheet.show_settings:
col.prop(spreadsheet, "separator", expand=True, text='Separator') col.prop(spreadsheet, "separator", expand=True, text='Separator')
if spreadsheet.format == 'CSV': if spreadsheet.format == 'csv':
col.prop(spreadsheet, "delimiter", expand=True, text='Delimiter') col.prop(spreadsheet, "delimiter", expand=True, text='Delimiter')
col.separator() if spreadsheet.format != 'Clipboard':
col.prop(spreadsheet, 'open_folder', text='Open Folder') col.separator()
col.prop(spreadsheet, 'export_path', text='Export Path') col.prop(spreadsheet, 'open_folder', text='Open Folder')
col.prop(spreadsheet, 'export_path', text='Export Path')
def execute(self, context): def execute(self, context):
#self.report({'ERROR'}, f'Export not implemented yet.') #self.report({'ERROR'}, f'Export not implemented yet.')
@ -499,7 +528,7 @@ class VSETB_OT_export_spreadsheet(Operator):
row += [strip.name] row += [strip.name]
elif cell.field_name == 'DESCRIPTION': elif cell.field_name == 'DESCRIPTION':
row += [strip.vsetb_strip_settings.description] row += [strip.vsetb_strip_settings.description]
elif cell.field_name == 'FRAMES': elif cell.field_name == 'NB_FRAMES':
row += [strip.frame_final_duration] row += [strip.frame_final_duration]
rows.append(row) rows.append(row)
@ -531,14 +560,14 @@ class VSETB_OT_export_spreadsheet(Operator):
#2023_04_11_kitsu_boris_ep01_shots #2023_04_11_kitsu_boris_ep01_shots
export_path.parent.mkdir(parents=True, exist_ok=True) export_path.parent.mkdir(parents=True, exist_ok=True)
if spreadsheet.format == 'CSV': if spreadsheet.format == 'csv':
print('Writing .csv file to', export_path) print('Writing .csv file to', export_path)
with open(str(export_path), 'w', newline='\n', encoding='utf-8') as f: with open(str(export_path), 'w', newline='\n', encoding='utf-8') as f:
writer = csv.writer(f, delimiter=spreadsheet.delimiter) writer = csv.writer(f, delimiter=spreadsheet.delimiter)
for row in rows: for row in rows:
writer.writerow(row) writer.writerow(row)
elif spreadsheet.format == 'XLSX': elif spreadsheet.format == 'xlsx':
try: try:
import openpyxl import openpyxl
except ModuleNotFoundError: except ModuleNotFoundError:
@ -558,6 +587,15 @@ class VSETB_OT_export_spreadsheet(Operator):
# Save the file # Save the file
workbook.save(str(export_path)) workbook.save(str(export_path))
elif spreadsheet.format == 'Clipboard':
csv_buffer = StringIO()
# Write CSV data to the StringIO buffer
csv_writer = csv.writer(csv_buffer, delimiter='\t')
csv_writer.writerows(rows)
context.window_manager.clipboard = csv_buffer.getvalue()
if spreadsheet.open_folder: if spreadsheet.open_folder:
open_file(export_path, select=True) open_file(export_path, select=True)
@ -570,6 +608,7 @@ classes = (
VSETB_MT_export_spreadsheet_presets, VSETB_MT_export_spreadsheet_presets,
VSETB_OT_spreadsheet_from_file, VSETB_OT_spreadsheet_from_file,
VSETB_OT_spreadsheet_from_clipboard, VSETB_OT_spreadsheet_from_clipboard,
VSETB_OT_spreadsheet_to_clipboard,
VSETB_OT_spreadsheet_cell_move, VSETB_OT_spreadsheet_cell_move,
VSETB_OT_export_spreadsheet, VSETB_OT_export_spreadsheet,
VSETB_OT_import_spreadsheet VSETB_OT_import_spreadsheet

View File

@ -137,7 +137,7 @@ def get_strip_render_path(strip, template):
strip_data = parse(strip.name, template=project.shot_template) strip_data = parse(strip.name, template=project.shot_template)
print(strip_data) #print(strip_data)
index = int(strip_data['index']) index = int(strip_data['index'])
@ -234,36 +234,31 @@ def render_strips(strips, template):
scn.render.filepath = render_path scn.render.filepath = render_path
''' '''
def render_strips(strips, template): def render_strip(strip, output):
output = os.path.abspath(bpy.path.abspath(output))
scn = bpy.context.scene scn = bpy.context.scene
scene_start = scn.frame_start scene_start = scn.frame_start
scene_end = scn.frame_end scene_end = scn.frame_end
scene_current = scn.frame_current
render_path = scn.render.filepath render_path = scn.render.filepath
for strip in strips: scn.frame_start = strip.frame_final_start
scn.frame_start = strip.frame_final_start scn.frame_end = strip.frame_final_end - 1
scn.frame_end = strip.frame_final_end - 1 scn.render.filepath = output
scn.render.filepath = str(get_strip_render_path(strip, template))
print(f'Render Strip to {scn.render.filepath}') print(f'Render Strip to {scn.render.filepath}')
bpy.ops.render.opengl(animation=True, sequencer=True) bpy.ops.render.opengl(animation=True, sequencer=True)
scn.frame_start = scene_start scn.frame_start = scene_start
scn.frame_end = scene_end scn.frame_end = scene_end
scn.frame_current = scene_current
scn.render.filepath = render_path scn.render.filepath = render_path
def import_edit(filepath, adapter="cmx_3600", channel='Shots'): def import_edit(filepath, adapter="cmx_3600", channel='Shots'):
opentimelineio = install_module('opentimelineio') opentimelineio = install_module('opentimelineio')
from opentimelineio.schema import ( from opentimelineio.schema import Clip
Clip,
ExternalReference,
Gap,
ImageSequenceReference,
Stack,
Timeline,
Track,
)
scn = bpy.context.scene scn = bpy.context.scene
sequencer = scn.sequence_editor.sequences sequencer = scn.sequence_editor.sequences

View File

@ -208,6 +208,7 @@ class VSETB_PT_exports(VSETB_main, Panel):
tracker_label = settings.tracker_name.title().replace('_', ' ') tracker_label = settings.tracker_name.title().replace('_', ' ')
layout.operator('vse_toolbox.upload_to_tracker', text=f'Upload to {tracker_label}', icon='EXPORT') layout.operator('vse_toolbox.upload_to_tracker', text=f'Upload to {tracker_label}', icon='EXPORT')
layout.operator('vse_toolbox.export_spreadsheet', text='Export Spreadsheet', icon='SPREADSHEET') layout.operator('vse_toolbox.export_spreadsheet', text='Export Spreadsheet', icon='SPREADSHEET')
layout.operator('vse_toolbox.export_edl', text='Export edl', icon='SEQ_SEQUENCER')
class VSETB_PT_casting(VSETB_main, Panel): class VSETB_PT_casting(VSETB_main, Panel):

View File

@ -3,6 +3,7 @@
import bpy import bpy
import os import os
from pathlib import Path from pathlib import Path
import re
from bpy.props import ( from bpy.props import (
BoolProperty, BoolProperty,
@ -16,7 +17,8 @@ from bpy.types import PropertyGroup, UIList
from pprint import pprint as pp from pprint import pprint as pp
from vse_toolbox.bl_utils import get_addon_prefs, get_scene_settings from vse_toolbox.bl_utils import get_addon_prefs, get_scene_settings
from vse_toolbox.constants import ASSET_PREVIEWS, TRACKERS, PREVIEWS_DIR from vse_toolbox.constants import ASSET_PREVIEWS, TRACKERS, PREVIEWS_DIR
from vse_toolbox.file_utils import norm_str from vse_toolbox.file_utils import norm_str, parse
from vse_toolbox.sequencer_utils import get_strip_sequence_name
def get_episodes_items(self, context): def get_episodes_items(self, context):
@ -187,7 +189,7 @@ def get_custom_name_items(self, context):
class SpreadsheetExport(PropertyGroup): class SpreadsheetExport(PropertyGroup):
use_custom_cells: BoolProperty(default=False) use_custom_cells: BoolProperty(default=False)
format : EnumProperty(items=[(i, i, '') for i in ('CSV', 'XLSX')]) format : EnumProperty(items=[(i, i, '') for i in ('csv', 'xlsx', 'Clipboard')])
separator : StringProperty(default='\\n') separator : StringProperty(default='\\n')
delimiter : StringProperty(default=';') delimiter : StringProperty(default=';')
export_path : StringProperty(default='//export') export_path : StringProperty(default='//export')
@ -245,7 +247,16 @@ class Project(PropertyGroup):
name="Shot Name", default="{sequence}_sh{index:04d}") name="Shot Name", default="{sequence}_sh{index:04d}")
render_template : StringProperty( render_template : StringProperty(
name="Render Name", default="//render/{strip_name}.{ext}") name="Movie Path", default="//render/{project_basename}.{ext}")
render_strip_template : StringProperty(
name="Strip Path", default="//render/shots/{strip}.{ext}")
render_per_strip: BoolProperty(name="Per Strip", default=True)
render_single_file: BoolProperty(name="Single File", default=False)
export_edl_template : StringProperty(
name="Edl Path", default="//render/{project_basename}.edl")
episode_name : EnumProperty(items=get_episodes_items, update=on_episode_updated) episode_name : EnumProperty(items=get_episodes_items, update=on_episode_updated)
episodes : CollectionProperty(type=Episode) episodes : CollectionProperty(type=Episode)
@ -260,6 +271,23 @@ class Project(PropertyGroup):
type : StringProperty() type : StringProperty()
@property
def active_episode(self):
return self.episodes.get(self.episode_name)
@property
def format_data(self):
data = {}
data['project'] = norm_str(self.name)
data['project_basename'] = data['project']
if self.active_episode:
data['episode'] = norm_str(self.episode_name)
data['project_basename'] = f"{data['project']}_{data['episode']}"
return data
def get_cell_types(self): def get_cell_types(self):
settings = get_scene_settings() settings = get_scene_settings()
project = settings.active_project project = settings.active_project
@ -293,7 +321,7 @@ class Project(PropertyGroup):
cell = spreadsheet.cells.add() cell = spreadsheet.cells.add()
cell.name = cell_name cell.name = cell_name
cell.export_name = 'Name' if cell_name == 'Shot' else cell_name cell.export_name = 'Name' if cell_name == 'Shot' else cell_name
cell.field_name = cell_name.upper() cell.field_name = norm_str(cell_name, format=str.upper)
cell.type = "SHOT" cell.type = "SHOT"
for metadata_type in self.metadata_types: for metadata_type in self.metadata_types:
@ -309,7 +337,7 @@ class Project(PropertyGroup):
cell = spreadsheet.cells.add() cell = spreadsheet.cells.add()
cell.name = asset_type.name cell.name = asset_type.name
cell.export_name = asset_type.name cell.export_name = asset_type.name
cell.field_name = asset_type.name.upper() cell.field_name = norm_str(asset_type.name, format=str.upper)
cell.type = "ASSET_TYPE" cell.type = "ASSET_TYPE"
def set_strip_metadata(self): def set_strip_metadata(self):
@ -337,6 +365,8 @@ class Project(PropertyGroup):
setattr(Metadata, field_name, prop) setattr(Metadata, field_name, prop)
class VSETB_UL_casting(UIList): class VSETB_UL_casting(UIList):
order_by_type : BoolProperty(default=False) order_by_type : BoolProperty(default=False)
@ -489,8 +519,24 @@ class VSETB_PGT_scene_settings(PropertyGroup):
def active_episode(self): def active_episode(self):
project = self.active_project project = self.active_project
if project: if project:
return project.episodes.get(project.episode_name) return project.active_episode
@property
def format_data(self):
data = {}
digit_matches = re.findall(r'(\d+)', bpy.data.filepath)
if len(digit_matches) == 1:
data['version'] = int(digit_matches[-1])
elif len(digit_matches) > 1:
data['increment'] = int(digit_matches[-1])
data['version'] = int(digit_matches[-2])
suffix = Path(bpy.context.scene.render.frame_path()).suffix
data['ext'] = suffix[1:]
return data
class VSETB_PGT_strip_settings(PropertyGroup): class VSETB_PGT_strip_settings(PropertyGroup):
casting : CollectionProperty(type=AssetCasting) casting : CollectionProperty(type=AssetCasting)
@ -506,6 +552,26 @@ class VSETB_PGT_strip_settings(PropertyGroup):
except IndexError: except IndexError:
return return
@property
def strip(self):
sequences = bpy.context.scene.sequence_editor.sequences_all
return next(s for s in sequences if s.vsetb_strip_settings == self)
@property
def format_data(self):
scn = bpy.context.scene
settings = get_scene_settings()
project = settings.active_project
strip = self.strip
data = parse(strip.name, template=project.shot_template)
data['index'] = int(data['index'])
data['sequence'] = get_strip_sequence_name(strip)
data['strip'] = strip.name
#data['shot'] = project.shot_template
return data
classes = ( classes = (
Asset, Asset,
AssetCasting, AssetCasting,