349 lines
11 KiB
Python
349 lines
11 KiB
Python
from os.path import expandvars
|
|
import bpy
|
|
from bpy.types import Operator
|
|
from bpy.props import (BoolProperty, StringProperty)
|
|
|
|
from vse_toolbox.sequencer_utils import (get_strips, rename_strips, set_channels,
|
|
get_channel_index, new_text_strip, get_strip_at, get_channel_name)
|
|
|
|
from vse_toolbox.bl_utils import get_scene_settings, get_strip_settings
|
|
|
|
|
|
class VSETB_OT_rename(Operator):
|
|
bl_idname = "vse_toolbox.strips_rename"
|
|
bl_label = "Rename Strips"
|
|
bl_description = "Rename Strips"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
#template : StringProperty(name="Strip Name", default="")
|
|
#increment : IntProperty(name="Increment", default=0)
|
|
channel_name : StringProperty(name="Channel Name", default="")
|
|
selected_only : BoolProperty(name="Selected Only", default=False)
|
|
#start_number : IntProperty(name="Start Number", default=0, min=0)
|
|
#by_sequence : BoolProperty(
|
|
# name="Reset By Sequence",
|
|
# description="Reset Start Number for each sequence",
|
|
# 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):
|
|
layout = self.layout
|
|
scn = context.scene
|
|
settings = get_scene_settings()
|
|
project = settings.active_project
|
|
|
|
col = layout.column()
|
|
col.use_property_split = True
|
|
col.use_property_decorate = False
|
|
|
|
if self.channel_name == 'Shots':
|
|
col.prop(project, 'shot_template', text='Shot Name')
|
|
col.prop(project, 'shot_start_number', text='Start Number')
|
|
col.prop(project, 'shot_increment', text='Increment')
|
|
col.prop(project, 'reset_by_sequence')
|
|
elif self.channel_name == 'Sequences':
|
|
col.prop(project, 'sequence_template' ,text='Sequence Name')
|
|
col.prop(project, 'sequence_start_number', text='Start Number')
|
|
col.prop(project, 'sequence_increment', text='Increment')
|
|
|
|
col.prop(self, 'selected_only')
|
|
|
|
def execute(self, context):
|
|
scn = context.scene
|
|
settings = get_scene_settings()
|
|
project = settings.active_project
|
|
|
|
strips = get_strips(channel=self.channel_name, selected_only=self.selected_only)
|
|
if self.channel_name == 'Shots':
|
|
rename_strips(strips,
|
|
template=project.shot_template,
|
|
increment=project.shot_increment, start_number=project.shot_start_number,
|
|
by_sequence=project.reset_by_sequence
|
|
)
|
|
|
|
if self.channel_name == 'Sequences':
|
|
rename_strips(strips,
|
|
template=project.sequence_template,
|
|
increment=project.sequence_increment, start_number=project.sequence_start_number
|
|
)
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class VSETB_OT_show_waveform(Operator):
|
|
bl_idname = "vse_toolbox.show_waveform"
|
|
bl_label = "Show Waveform"
|
|
bl_description = "Show Waveform of all audio strips"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
enabled : BoolProperty(default=True)
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
def execute(self, context):
|
|
scn = context.scene
|
|
|
|
for strip in get_strips(channel='Audio'):
|
|
strip.show_waveform = self.enabled
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class VSETB_OT_set_sequencer(Operator):
|
|
bl_idname = "vse_toolbox.set_sequencer"
|
|
bl_label = "Set Sequencer"
|
|
bl_description = "Set resolution, frame end and channel names"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
return True
|
|
|
|
def execute(self, context):
|
|
scn = context.scene
|
|
|
|
set_channels()
|
|
movies = get_strips(channel='Movie')
|
|
movie = None
|
|
if movies:
|
|
movie = movies[0]
|
|
movie.transform.scale_x = movie.transform.scale_y = 1
|
|
elem = movie.strip_elem_from_frame(scn.frame_current)
|
|
scn.render.resolution_x = elem.orig_width
|
|
scn.render.resolution_y = elem.orig_height
|
|
else:
|
|
self.report({'INFO'}, f'Cannot set Resolution. No Movie Found.')
|
|
|
|
scn.view_settings.view_transform = 'Standard'
|
|
scn.render.image_settings.file_format = 'FFMPEG'
|
|
scn.render.ffmpeg.gopsize = 5
|
|
scn.render.ffmpeg.constant_rate_factor = 'HIGH'
|
|
scn.render.ffmpeg.format = 'QUICKTIME'
|
|
scn.render.ffmpeg.audio_codec = 'AAC'
|
|
scn.render.ffmpeg.audio_codec = 'MP3'
|
|
scn.render.ffmpeg.audio_mixrate = 44100
|
|
scn.render.ffmpeg.audio_bitrate = 128
|
|
|
|
shots = get_strips(channel='Shots')
|
|
if shots:
|
|
scn.frame_end = shots[-1].frame_final_end -1
|
|
elif movie:
|
|
scn.frame_end = movie.frame_final_end -1
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class VSETB_OT_set_stamps(Operator):
|
|
bl_idname = "vse_toolbox.set_stamps"
|
|
bl_label = "Set Stamps"
|
|
bl_description = "Set Stamps on Video"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
def execute(self, context):
|
|
scn = context.scene
|
|
settings = get_scene_settings()
|
|
project = settings.active_project
|
|
#strip_settings = get_strip_settings()
|
|
channel_index = get_channel_index('Stamps')
|
|
|
|
for strip in get_strips('Stamps'):
|
|
if strip.type == 'META':
|
|
scn.sequence_editor.sequences.remove(strip)
|
|
|
|
bpy.ops.sequencer.select_all(action='DESELECT')
|
|
|
|
height = scn.render.resolution_y
|
|
width = scn.render.resolution_x
|
|
ratio = (height / 1080)
|
|
margin = 0.01
|
|
box_margin = 0.005
|
|
font_size = int(24*ratio)
|
|
|
|
crop_x = int(width * 0.4)
|
|
crop_max_y = int(height - font_size*2)
|
|
#crop_min_y = int(scn.render.resolution_y * 0.01)
|
|
|
|
stamp_params = dict(start=scn.frame_start, end=scn.frame_end,
|
|
font_size=font_size, y=margin, box_margin=box_margin, select=True, box_color=(0, 0, 0, 0.5))
|
|
|
|
# Project Name
|
|
project_text = '{project_name}'
|
|
if project.type == 'TVSHOW':
|
|
project_text = '{project_name} / {episode_name}'
|
|
project_strip_stamp = new_text_strip('project_name_stamp', channel=1, **stamp_params,
|
|
text=project_text, x=0.01, align_x='LEFT', align_y='BOTTOM')
|
|
|
|
project_strip_stamp.crop.max_x = crop_x * 2
|
|
project_strip_stamp.crop.max_y = crop_max_y
|
|
|
|
# Shot Name
|
|
|
|
shot_strip_stamp = new_text_strip('shot_name_stamp', channel=2, **stamp_params,
|
|
text='{sequence_name} / {shot_name}', align_y='BOTTOM')
|
|
|
|
shot_strip_stamp.crop.min_x = crop_x
|
|
shot_strip_stamp.crop.max_x = crop_x
|
|
shot_strip_stamp.crop.max_y = crop_max_y
|
|
|
|
# Frame Range
|
|
frame_strip_stamp = new_text_strip('frame_range_stamp', channel=3, **stamp_params,
|
|
text='{shot_frame} / {shot_duration}', x=0.99, align_x='RIGHT', align_y='BOTTOM')
|
|
|
|
frame_strip_stamp.crop.min_x = crop_x *2
|
|
frame_strip_stamp.crop.max_y = crop_max_y
|
|
|
|
bpy.ops.sequencer.meta_make()
|
|
stamps_strip = context.active_sequence_strip
|
|
stamps_strip.name = 'Stamps'
|
|
stamps_strip.channel = channel_index
|
|
|
|
#stamps_strip = scn.sequence_editor.sequences.new_meta('Stamps', scn.frame_start, scn.frame_end)
|
|
#stamps_strip.channel = get_channel_index('Stamps')
|
|
scn.frame_set(scn.frame_current) # For update stamps
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class VSETB_OT_previous_shot(Operator):
|
|
bl_idname = "vse_toolbox.previous_shot"
|
|
bl_label = "Jump to Previous Shot"
|
|
bl_description = "Jump to Previous Shot"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
def execute(self, context):
|
|
strips = get_strips('Shots')
|
|
if not strips:
|
|
return {"CANCELLED"}
|
|
|
|
active_strip = get_strip_at('Shots')
|
|
if active_strip is strips[0]:
|
|
return {"CANCELLED"}
|
|
|
|
active_strip_index = strips.index(active_strip)
|
|
next_shot = strips[active_strip_index - 1]
|
|
context.scene.frame_set(next_shot.frame_final_start)
|
|
|
|
bpy.ops.sequencer.select_all(action="DESELECT")
|
|
next_shot.select = True
|
|
context.scene.sequence_editor.active_strip = next_shot
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
class VSETB_OT_next_shot(Operator):
|
|
bl_idname = "vse_toolbox.next_shot"
|
|
bl_label = "Jump to Next Shot"
|
|
bl_description = "Jump to Next Shot"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
def execute(self, context):
|
|
|
|
strips = get_strips('Shots')
|
|
if not strips:
|
|
return {"CANCELLED"}
|
|
|
|
active_strip = get_strip_at('Shots')
|
|
if active_strip is strips[-1]:
|
|
return {"CANCELLED"}
|
|
|
|
active_strip_index = strips.index(active_strip)
|
|
next_shot = strips[active_strip_index + 1]
|
|
context.scene.frame_set(next_shot.frame_final_start)
|
|
|
|
bpy.ops.sequencer.select_all(action="DESELECT")
|
|
next_shot.select = True
|
|
context.scene.sequence_editor.active_strip = next_shot
|
|
|
|
return {"FINISHED"}
|
|
|
|
class VSETB_OT_open_shot_dir(Operator):
|
|
bl_idname = "vse_toolbox.open_shot_dir"
|
|
bl_label = "Open Shot Dir"
|
|
bl_description = "Open Shot Dir"
|
|
bl_options = {"REGISTER", "UNDO"}
|
|
|
|
@classmethod
|
|
def poll(cls, context):
|
|
strip = context.active_sequence_strip
|
|
return strip and get_channel_name(strip) == 'Shots'
|
|
|
|
def execute(self, context):
|
|
strip = context.active_sequence_strip
|
|
settings = get_scene_settings()
|
|
project = settings.active_project
|
|
|
|
strip_settings = get_strip_settings()
|
|
|
|
format_data = {**settings.format_data, **project.format_data, **strip_settings.format_data}
|
|
|
|
shot_dir_template = expandvars(project.shot_dir_template)
|
|
shot_dir_path = shot_dir_template.format(**format_data)
|
|
bpy.ops.wm.path_open(filepath=shot_dir_path)
|
|
|
|
return {"FINISHED"}
|
|
|
|
|
|
addon_keymaps = []
|
|
def register_keymaps():
|
|
addon = bpy.context.window_manager.keyconfigs.addon
|
|
|
|
if not addon:
|
|
return
|
|
|
|
#print('VSE Toolbox Keymaps Register')
|
|
|
|
km = addon.keymaps.new(name="Sequencer", space_type="SEQUENCE_EDITOR")
|
|
|
|
kmi = km.keymap_items.new('vse_toolbox.previous_shot', type='LEFT_ARROW', value='PRESS', ctrl=True)
|
|
addon_keymaps.append((km, kmi))
|
|
|
|
kmi = km.keymap_items.new('vse_toolbox.next_shot', type='RIGHT_ARROW', value='PRESS', ctrl=True)
|
|
addon_keymaps.append((km, kmi))
|
|
|
|
|
|
def unregister_keymaps():
|
|
#print('unregister_keymaps', addon_keymaps)
|
|
for km, kmi in addon_keymaps:
|
|
if kmi in list(km.keymap_items):
|
|
km.keymap_items.remove(kmi)
|
|
|
|
addon_keymaps.clear()
|
|
|
|
|
|
|
|
classes = (
|
|
VSETB_OT_rename,
|
|
VSETB_OT_set_sequencer,
|
|
VSETB_OT_set_stamps,
|
|
VSETB_OT_show_waveform,
|
|
VSETB_OT_previous_shot,
|
|
VSETB_OT_next_shot,
|
|
VSETB_OT_open_shot_dir
|
|
)
|
|
|
|
def register():
|
|
for cls in classes:
|
|
bpy.utils.register_class(cls)
|
|
|
|
register_keymaps()
|
|
|
|
|
|
def unregister():
|
|
for cls in reversed(classes):
|
|
bpy.utils.unregister_class(cls)
|
|
|
|
unregister_keymaps()
|