export background
parent
48dddb1905
commit
beb85721a9
|
@ -36,8 +36,8 @@ if 'bpy' in locals():
|
|||
import bpy
|
||||
|
||||
def register():
|
||||
print('Register update script handler')
|
||||
bpy.app.handlers.frame_change_post.append(update_text_strips)
|
||||
bpy.app.handlers.render_pre.append(update_text_strips)
|
||||
|
||||
if bpy.app.background:
|
||||
return
|
||||
|
@ -51,6 +51,7 @@ def register():
|
|||
|
||||
def unregister():
|
||||
bpy.app.handlers.frame_change_post.remove(update_text_strips)
|
||||
bpy.app.handlers.render_pre.remove(update_text_strips)
|
||||
|
||||
try:
|
||||
bpy.utils.previews.remove(ASSET_PREVIEWS)
|
||||
|
|
57
bl_utils.py
57
bl_utils.py
|
@ -2,9 +2,19 @@
|
|||
"""
|
||||
Generic Blender functions
|
||||
"""
|
||||
import os
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import json
|
||||
from textwrap import dedent
|
||||
|
||||
import bpy
|
||||
|
||||
|
||||
def abspath(path):
|
||||
path = os.path.abspath(bpy.path.abspath(path))
|
||||
return Path(path)
|
||||
|
||||
def get_scene_settings():
|
||||
return bpy.context.scene.vsetb_settings
|
||||
|
||||
|
@ -17,7 +27,27 @@ def get_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]
|
||||
|
||||
if background:
|
||||
|
@ -31,6 +61,9 @@ def get_bl_cmd(blender=None, background=False, focus=True, blendfile=None, scrip
|
|||
|
||||
if blendfile:
|
||||
cmd += [str(blendfile)]
|
||||
|
||||
if output:
|
||||
cmd += ['-o', str(output)]
|
||||
|
||||
if script:
|
||||
cmd += ['--python', str(script)]
|
||||
|
@ -49,6 +82,28 @@ def get_bl_cmd(blender=None, background=False, focus=True, blendfile=None, scrip
|
|||
|
||||
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():
|
||||
addon_name = __package__.split('.')[0]
|
||||
return bpy.context.preferences.addons[addon_name].preferences
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
# 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)
|
||||
|
||||
modules = (
|
||||
addon,
|
||||
casting,
|
||||
imports,
|
||||
render,
|
||||
exports,
|
||||
sequencer,
|
||||
spreadsheet,
|
||||
tracker
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
import json
|
||||
|
||||
import bpy
|
||||
from bpy.types import PropertyGroup, Operator
|
||||
from bpy.types import Context, Event, PropertyGroup, Operator
|
||||
from bpy.props import (CollectionProperty, EnumProperty, StringProperty)
|
||||
|
||||
from vse_toolbox.constants import CASTING_BUFFER
|
||||
|
@ -249,15 +249,27 @@ class VSETB_OT_copy_casting(Operator):
|
|||
class VSETB_OT_paste_casting(Operator):
|
||||
bl_idname = "vse_toolbox.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"}
|
||||
|
||||
mode : EnumProperty(items=[(m, m.title(), '') for m in ('REPLACE', 'ADD', 'REMOVE')])
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
active_strip = context.scene.sequence_editor.active_strip
|
||||
if active_strip:
|
||||
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):
|
||||
scn = context.scene
|
||||
strip_settings = get_strip_settings()
|
||||
|
@ -267,19 +279,33 @@ class VSETB_OT_paste_casting(Operator):
|
|||
return {"CANCELLED"}
|
||||
|
||||
casting_datas = json.loads(CASTING_BUFFER.read_text())
|
||||
casting_ids = set(c['id'] for c in casting_datas)
|
||||
|
||||
for strip in context.selected_sequences:
|
||||
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:
|
||||
|
||||
item = strip.vsetb_strip_settings.casting.add()
|
||||
if self.mode == 'REMOVE':
|
||||
|
||||
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']
|
||||
item.id = casting_data['id']
|
||||
item['_name'] = casting_data['_name']
|
||||
if strip_settings.casting_index != 0:
|
||||
strip_settings.casting_index -= 1
|
||||
|
||||
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"}
|
||||
|
||||
|
|
|
@ -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)
|
|
@ -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)
|
|
@ -171,6 +171,40 @@ class VSETB_OT_spreadsheet_from_clipboard(Operator):
|
|||
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):
|
||||
bl_idname = "vse_toolbox.import_spreadsheet"
|
||||
bl_label = "Import Spreadsheet"
|
||||
|
@ -368,13 +402,7 @@ class VSETB_OT_import_spreadsheet(Operator):
|
|||
|
||||
strip_settings.casting.update()
|
||||
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"}
|
||||
|
||||
|
@ -446,12 +474,13 @@ class VSETB_OT_export_spreadsheet(Operator):
|
|||
row.prop(spreadsheet, 'show_settings', text='', icon='PREFERENCES')
|
||||
if spreadsheet.show_settings:
|
||||
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.separator()
|
||||
col.prop(spreadsheet, 'open_folder', text='Open Folder')
|
||||
col.prop(spreadsheet, 'export_path', text='Export Path')
|
||||
if spreadsheet.format != 'Clipboard':
|
||||
col.separator()
|
||||
col.prop(spreadsheet, 'open_folder', text='Open Folder')
|
||||
col.prop(spreadsheet, 'export_path', text='Export Path')
|
||||
|
||||
def execute(self, context):
|
||||
#self.report({'ERROR'}, f'Export not implemented yet.')
|
||||
|
@ -499,7 +528,7 @@ class VSETB_OT_export_spreadsheet(Operator):
|
|||
row += [strip.name]
|
||||
elif cell.field_name == 'DESCRIPTION':
|
||||
row += [strip.vsetb_strip_settings.description]
|
||||
elif cell.field_name == 'FRAMES':
|
||||
elif cell.field_name == 'NB_FRAMES':
|
||||
row += [strip.frame_final_duration]
|
||||
|
||||
rows.append(row)
|
||||
|
@ -531,14 +560,14 @@ class VSETB_OT_export_spreadsheet(Operator):
|
|||
#2023_04_11_kitsu_boris_ep01_shots
|
||||
export_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if spreadsheet.format == 'CSV':
|
||||
if spreadsheet.format == 'csv':
|
||||
print('Writing .csv file to', export_path)
|
||||
with open(str(export_path), 'w', newline='\n', encoding='utf-8') as f:
|
||||
writer = csv.writer(f, delimiter=spreadsheet.delimiter)
|
||||
for row in rows:
|
||||
writer.writerow(row)
|
||||
|
||||
elif spreadsheet.format == 'XLSX':
|
||||
elif spreadsheet.format == 'xlsx':
|
||||
try:
|
||||
import openpyxl
|
||||
except ModuleNotFoundError:
|
||||
|
@ -558,6 +587,15 @@ class VSETB_OT_export_spreadsheet(Operator):
|
|||
|
||||
# Save the file
|
||||
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:
|
||||
open_file(export_path, select=True)
|
||||
|
@ -570,6 +608,7 @@ classes = (
|
|||
VSETB_MT_export_spreadsheet_presets,
|
||||
VSETB_OT_spreadsheet_from_file,
|
||||
VSETB_OT_spreadsheet_from_clipboard,
|
||||
VSETB_OT_spreadsheet_to_clipboard,
|
||||
VSETB_OT_spreadsheet_cell_move,
|
||||
VSETB_OT_export_spreadsheet,
|
||||
VSETB_OT_import_spreadsheet
|
||||
|
|
|
@ -137,7 +137,7 @@ def get_strip_render_path(strip, template):
|
|||
|
||||
strip_data = parse(strip.name, template=project.shot_template)
|
||||
|
||||
print(strip_data)
|
||||
#print(strip_data)
|
||||
|
||||
index = int(strip_data['index'])
|
||||
|
||||
|
@ -234,36 +234,31 @@ def render_strips(strips, template):
|
|||
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
|
||||
scene_start = scn.frame_start
|
||||
scene_end = scn.frame_end
|
||||
scene_current = scn.frame_current
|
||||
render_path = scn.render.filepath
|
||||
|
||||
for strip in strips:
|
||||
scn.frame_start = strip.frame_final_start
|
||||
scn.frame_end = strip.frame_final_end - 1
|
||||
scn.render.filepath = str(get_strip_render_path(strip, template))
|
||||
scn.frame_start = strip.frame_final_start
|
||||
scn.frame_end = strip.frame_final_end - 1
|
||||
scn.render.filepath = output
|
||||
|
||||
print(f'Render Strip to {scn.render.filepath}')
|
||||
bpy.ops.render.opengl(animation=True, sequencer=True)
|
||||
print(f'Render Strip to {scn.render.filepath}')
|
||||
bpy.ops.render.opengl(animation=True, sequencer=True)
|
||||
|
||||
scn.frame_start = scene_start
|
||||
scn.frame_end = scene_end
|
||||
scn.frame_current = scene_current
|
||||
scn.render.filepath = render_path
|
||||
|
||||
def import_edit(filepath, adapter="cmx_3600", channel='Shots'):
|
||||
opentimelineio = install_module('opentimelineio')
|
||||
|
||||
from opentimelineio.schema import (
|
||||
Clip,
|
||||
ExternalReference,
|
||||
Gap,
|
||||
ImageSequenceReference,
|
||||
Stack,
|
||||
Timeline,
|
||||
Track,
|
||||
)
|
||||
from opentimelineio.schema import Clip
|
||||
|
||||
scn = bpy.context.scene
|
||||
sequencer = scn.sequence_editor.sequences
|
||||
|
|
|
@ -208,6 +208,7 @@ class VSETB_PT_exports(VSETB_main, Panel):
|
|||
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.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):
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import bpy
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
from bpy.props import (
|
||||
BoolProperty,
|
||||
|
@ -16,7 +17,8 @@ from bpy.types import PropertyGroup, UIList
|
|||
from pprint import pprint as pp
|
||||
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.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):
|
||||
|
@ -187,7 +189,7 @@ def get_custom_name_items(self, context):
|
|||
|
||||
class SpreadsheetExport(PropertyGroup):
|
||||
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')
|
||||
delimiter : StringProperty(default=';')
|
||||
export_path : StringProperty(default='//export')
|
||||
|
@ -245,7 +247,16 @@ class Project(PropertyGroup):
|
|||
name="Shot Name", default="{sequence}_sh{index:04d}")
|
||||
|
||||
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)
|
||||
episodes : CollectionProperty(type=Episode)
|
||||
|
@ -260,6 +271,23 @@ class Project(PropertyGroup):
|
|||
|
||||
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):
|
||||
settings = get_scene_settings()
|
||||
project = settings.active_project
|
||||
|
@ -293,7 +321,7 @@ class Project(PropertyGroup):
|
|||
cell = spreadsheet.cells.add()
|
||||
cell.name = 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"
|
||||
|
||||
for metadata_type in self.metadata_types:
|
||||
|
@ -309,7 +337,7 @@ class Project(PropertyGroup):
|
|||
cell = spreadsheet.cells.add()
|
||||
cell.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"
|
||||
|
||||
def set_strip_metadata(self):
|
||||
|
@ -337,6 +365,8 @@ class Project(PropertyGroup):
|
|||
setattr(Metadata, field_name, prop)
|
||||
|
||||
|
||||
|
||||
|
||||
class VSETB_UL_casting(UIList):
|
||||
|
||||
order_by_type : BoolProperty(default=False)
|
||||
|
@ -489,8 +519,24 @@ class VSETB_PGT_scene_settings(PropertyGroup):
|
|||
def active_episode(self):
|
||||
project = self.active_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):
|
||||
casting : CollectionProperty(type=AssetCasting)
|
||||
|
@ -506,6 +552,26 @@ class VSETB_PGT_strip_settings(PropertyGroup):
|
|||
except IndexError:
|
||||
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 = (
|
||||
Asset,
|
||||
AssetCasting,
|
||||
|
|
Loading…
Reference in New Issue