Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'kinoraw_tools/operators_extra_actions.py')
-rw-r--r--kinoraw_tools/operators_extra_actions.py1316
1 files changed, 1316 insertions, 0 deletions
diff --git a/kinoraw_tools/operators_extra_actions.py b/kinoraw_tools/operators_extra_actions.py
new file mode 100644
index 00000000..cae4a5d4
--- /dev/null
+++ b/kinoraw_tools/operators_extra_actions.py
@@ -0,0 +1,1316 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+import bpy
+
+import random
+import math
+import os, sys
+
+from bpy.props import IntProperty
+from bpy.props import FloatProperty
+from bpy.props import EnumProperty
+from bpy.props import BoolProperty
+from bpy.props import StringProperty
+
+from . import functions
+from . import exiftool
+
+# ------------------------------
+
+# SKIP ONE SECOND
+class Sequencer_Extra_FrameSkip(bpy.types.Operator):
+ bl_label = 'Skip One Second'
+ bl_idname = 'screenextra.frame_skip'
+ bl_description = 'Skip through the Timeline by one-second increments'
+ bl_options = {'REGISTER', 'UNDO'}
+ back = BoolProperty(
+ name='Back',
+ default=False)
+
+ def execute(self, context):
+ one_second = bpy.context.scene.render.fps
+ if self.back == True:
+ one_second *= -1
+ bpy.ops.screen.frame_offset(delta=one_second)
+ return {'FINISHED'}
+
+
+# TRIM TIMELINE
+class Sequencer_Extra_TrimTimeline(bpy.types.Operator):
+ bl_label = 'Trim to Timeline Content'
+ bl_idname = 'timeextra.trimtimeline'
+ bl_description = 'Automatically set start and end frames'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ scn = context.scene
+ if scn and scn.sequence_editor:
+ return scn.sequence_editor.sequences
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+
+ frame_start = 300000
+ frame_end = -300000
+ for i in seq.sequences:
+ try:
+ if i.frame_final_start < frame_start:
+ frame_start = i.frame_final_start
+ if i.frame_final_end > frame_end:
+ frame_end = i.frame_final_end - 1
+ except AttributeError:
+ pass
+
+ if frame_start != 300000:
+ scn.frame_start = frame_start
+ if frame_end != -300000:
+ scn.frame_end = frame_end
+
+ bpy.ops.sequencer.view_all()
+
+ return {'FINISHED'}
+
+
+# TRIM TIMELINE TO SELECTION
+class Sequencer_Extra_TrimTimelineToSelection(bpy.types.Operator):
+ bl_label = 'Trim to Selection'
+ bl_idname = 'timeextra.trimtimelinetoselection'
+ bl_description = 'Set start and end frames to selection'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ scn = context.scene
+ if scn and scn.sequence_editor:
+ return scn.sequence_editor.sequences
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+
+ frame_start = 300000
+ frame_end = -300000
+ for i in seq.sequences:
+ try:
+ if i.frame_final_start < frame_start and i.select == True:
+ frame_start = i.frame_final_start
+ if i.frame_final_end > frame_end and i.select == True:
+ frame_end = i.frame_final_end - 1
+ except AttributeError:
+ pass
+
+ if frame_start != 300000:
+ scn.frame_start = frame_start
+ if frame_end != -300000:
+ scn.frame_end = frame_end
+
+ bpy.ops.sequencer.view_selected()
+ return {'FINISHED'}
+
+# ------------------------------
+
+
+# OPEN IMAGE WITH EDITOR AND create movie clip strip
+class Sequencer_Extra_CreateMovieclip(bpy.types.Operator):
+ bl_label = 'Create a Movieclip from selected strip'
+ bl_idname = 'sequencerextra.createmovieclip'
+ bl_description = 'Create a Movieclip strip from a MOVIE or IMAGE strip'
+
+ """
+ When a movie or image strip is selected, this operator creates a movieclip
+ or find the correspondent movieclip that already exists for this footage,
+ and add a VSE clip strip with same cuts the original strip has.
+ It can convert movie strips and image sequences, both with hard cuts or
+ soft cuts.
+ """
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return strip.type in ('MOVIE', 'IMAGE')
+ else:
+ return False
+
+ def execute(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+
+ if strip.type == 'MOVIE':
+ #print("movie", strip.frame_start)
+ path = strip.filepath
+ #print(path)
+ data_exists = False
+ for i in bpy.data.movieclips:
+ if i.filepath == path:
+ data_exists = True
+ data = i
+ newstrip = None
+ if data_exists == False:
+ try:
+ data = bpy.data.movieclips.load(filepath=path)
+ newstrip = bpy.ops.sequencer.movieclip_strip_add(\
+ replace_sel=True, overlap=False, clip=data.name)
+ newstrip = functions.act_strip(context)
+ newstrip.frame_start = strip.frame_start\
+ - strip.animation_offset_start
+ tin = strip.frame_offset_start + strip.frame_start
+ tout = tin + strip.frame_final_duration
+ #print(newstrip.frame_start, strip.frame_start, tin, tout)
+ functions.triminout(newstrip, tin, tout)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ else:
+ try:
+ newstrip = bpy.ops.sequencer.movieclip_strip_add(\
+ replace_sel=True, overlap=False, clip=data.name)
+ newstrip = functions.act_strip(context)
+ newstrip.frame_start = strip.frame_start\
+ - strip.animation_offset_start
+ # i need to declare the strip this way in order
+ # to get triminout() working
+ clip = bpy.context.scene.sequence_editor.sequences[\
+ newstrip.name]
+ # i cannot change these movie clip attributes via scripts
+ # but it works in the python console...
+ #clip.animation_offset_start = strip.animation.offset_start
+ #clip.animation_offset_end = strip.animation.offset_end
+ #clip.frame_final_duration = strip.frame_final_duration
+ tin = strip.frame_offset_start + strip.frame_start
+ tout = tin + strip.frame_final_duration
+ #print(newstrip.frame_start, strip.frame_start, tin, tout)
+ functions.triminout(clip, tin, tout)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ elif strip.type == 'IMAGE':
+ #print("image")
+ base_dir = bpy.path.abspath(strip.directory)
+ scn.frame_current = strip.frame_start -\
+ strip.animation_offset_start
+ # searching for the first frame of the sequencer. This is mandatory
+ # for hard cutted sequence strips to be correctly converted,
+ # avoiding to create a new movie clip if not needed
+ filename = sorted(os.listdir(base_dir))[0]
+ path = os.path.join(base_dir, filename)
+ #print(path)
+ data_exists = False
+ for i in bpy.data.movieclips:
+ #print(i.filepath, path)
+ if i.filepath == path:
+ data_exists = True
+ data = i
+ #print(data_exists)
+ if data_exists == False:
+ try:
+ data = bpy.data.movieclips.load(filepath=path)
+ newstrip = bpy.ops.sequencer.movieclip_strip_add(\
+ replace_sel=True, overlap=False,\
+ clip=data.name)
+ newstrip = functions.act_strip(context)
+ newstrip.frame_start = strip.frame_start\
+ - strip.animation_offset_start
+ clip = bpy.context.scene.sequence_editor.sequences[\
+ newstrip.name]
+ tin = strip.frame_offset_start + strip.frame_start
+ tout = tin + strip.frame_final_duration
+ #print(newstrip.frame_start, strip.frame_start, tin, tout)
+ functions.triminout(clip, tin, tout)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ else:
+ try:
+ newstrip = bpy.ops.sequencer.movieclip_strip_add(\
+ replace_sel=True, overlap=False, clip=data.name)
+ newstrip = functions.act_strip(context)
+ newstrip.frame_start = strip.frame_start\
+ - strip.animation_offset_start
+ # need to declare the strip this way in order
+ # to get triminout() working
+ clip = bpy.context.scene.sequence_editor.sequences[\
+ newstrip.name]
+ # cannot change this atributes via scripts...
+ # but it works in the python console...
+ #clip.animation_offset_start = strip.animation.offset_start
+ #clip.animation_offset_end = strip.animation.offset_end
+ #clip.frame_final_duration = strip.frame_final_duration
+ tin = strip.frame_offset_start + strip.frame_start
+ tout = tin + strip.frame_final_duration
+ #print(newstrip.frame_start, strip.frame_start, tin, tout)
+ functions.triminout(clip, tin, tout)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ # show the new clip in a movie clip editor, if available.
+ if strip.type == 'MOVIE' or 'IMAGE':
+ for a in context.window.screen.areas:
+ if a.type == 'CLIP_EDITOR':
+ a.spaces[0].clip = data
+
+ return {'FINISHED'}
+
+
+# OPEN IMAGE WITH EDITOR
+class Sequencer_Extra_Edit(bpy.types.Operator):
+ bl_label = 'Open with Editor'
+ bl_idname = 'sequencerextra.edit'
+ bl_description = 'Open with Movie Clip or Image Editor'
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return strip.type in ('MOVIE', 'IMAGE')
+ else:
+ return False
+
+ def execute(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ data_exists = False
+
+ if strip.type == 'MOVIE':
+ path = strip.filepath
+
+ for i in bpy.data.movieclips:
+ if i.filepath == path:
+ data_exists = True
+ data = i
+
+ if data_exists == False:
+ try:
+ data = bpy.data.movieclips.load(filepath=path)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ elif strip.type == 'IMAGE':
+ base_dir = bpy.path.abspath(strip.directory)
+ strip_elem = strip.strip_elem_from_frame(scn.frame_current)
+ elem_name = strip_elem.filename
+ path = base_dir + elem_name
+
+ for i in bpy.data.images:
+ if i.filepath == path:
+ data_exists = True
+ data = i
+
+ if data_exists == False:
+ try:
+ data = bpy.data.images.load(filepath=path)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ if strip.type == 'MOVIE':
+ for a in context.window.screen.areas:
+ if a.type == 'CLIP_EDITOR':
+ a.spaces[0].clip = data
+ elif strip.type == 'IMAGE':
+ for a in context.window.screen.areas:
+ if a.type == 'IMAGE_EDITOR':
+ a.spaces[0].image = data
+
+ return {'FINISHED'}
+
+
+# OPEN IMAGE WITH EXTERNAL EDITOR
+class Sequencer_Extra_EditExternally(bpy.types.Operator):
+ bl_label = 'Open with External Editor'
+ bl_idname = 'sequencerextra.editexternally'
+ bl_description = 'Open with the default external image editor'
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return strip.type == 'IMAGE'
+ else:
+ return False
+
+ def execute(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ base_dir = bpy.path.abspath(strip.directory)
+ strip_elem = strip.strip_elem_from_frame(scn.frame_current)
+ path = base_dir + strip_elem.filename
+
+ try:
+ bpy.ops.image.external_edit(filepath=path)
+ except:
+ self.report({'ERROR_INVALID_INPUT'},
+ 'Please specify an Image Editor in Preferences > File')
+ return {'CANCELLED'}
+
+ return {'FINISHED'}
+
+
+# FILE NAME TO STRIP NAME
+class Sequencer_Extra_FileNameToStripName(bpy.types.Operator):
+ bl_label = 'File Name to Selected Strips Name'
+ bl_idname = 'sequencerextra.striprename'
+ bl_description = 'Set strip name to input file name'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ scn = context.scene
+ if scn and scn.sequence_editor:
+ return scn.sequence_editor.sequences
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ selection = False
+ for i in seq.sequences:
+ if i.select == True:
+ if i.type == 'IMAGE' and not i.mute:
+ selection = True
+ i.name = i.elements[0].filename
+ if (i.type == 'SOUND' or i.type == 'MOVIE') and not i.mute:
+ selection = True
+ i.name = bpy.path.display_name_from_filepath(i.filepath)
+ if selection == False:
+ self.report({'ERROR_INVALID_INPUT'},
+ 'No image or movie strip selected')
+ return {'CANCELLED'}
+ return {'FINISHED'}
+
+
+# ------------------------------
+
+
+# NAVIGATE UP
+class Sequencer_Extra_NavigateUp(bpy.types.Operator):
+ bl_label = 'Navigate Up'
+ bl_idname = 'sequencerextra.navigateup'
+ bl_description = 'Move to Parent Timeline'
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ try:
+ if context.scene.sequence_editor.meta_stack:
+ return True
+ else:
+ return False
+ except:
+ return False
+
+ def execute(self, context):
+ if (functions.act_strip(context)):
+ strip = functions.act_strip(context)
+ seq_type = strip.type
+ if seq_type == 'META':
+ context.scene.sequence_editor.active_strip = None
+
+ bpy.ops.sequencer.meta_toggle()
+ return {'FINISHED'}
+
+
+# ------------------------------
+
+
+# RIPPLE DELETE
+class Sequencer_Extra_RippleDelete(bpy.types.Operator):
+ bl_label = 'Ripple Delete'
+ bl_idname = 'sequencerextra.rippledelete'
+ bl_description = 'Delete a strip and shift back following ones'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ #strip = functions.act_strip(context)
+ for strip in context.selected_editable_sequences:
+ cut_frame = strip.frame_final_start
+ next_edit = 300000
+ bpy.ops.sequencer.select_all(action='DESELECT')
+ strip.select = True
+ bpy.ops.sequencer.delete()
+ striplist = []
+ for i in seq.sequences:
+ try:
+ if (i.frame_final_start > cut_frame
+ and not i.mute):
+ if i.frame_final_start < next_edit:
+ next_edit = i.frame_final_start
+ if not i.mute:
+ striplist.append(i)
+ except AttributeError:
+ pass
+
+ if next_edit == 300000:
+ return {'FINISHED'}
+ ripple_length = next_edit - cut_frame
+ for i in range(len(striplist)):
+ str = striplist[i]
+ try:
+ if str.frame_final_start > cut_frame:
+ str.frame_start = str.frame_start - ripple_length
+ except AttributeError:
+ pass
+ bpy.ops.sequencer.reload()
+ return {'FINISHED'}
+
+
+# RIPPLE CUT
+class Sequencer_Extra_RippleCut(bpy.types.Operator):
+ bl_label = 'Ripple Cut'
+ bl_idname = 'sequencerextra.ripplecut'
+ bl_description = 'Move a strip to buffer and shift back following ones'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ strip = functions.act_strip(context)
+ bpy.ops.sequencer.select_all(action='DESELECT')
+ strip.select = True
+ temp_cf = scn.frame_current
+ scn.frame_current = strip.frame_final_start
+ bpy.ops.sequencer.copy()
+ scn.frame_current = temp_cf
+
+ bpy.ops.sequencerextra.rippledelete()
+ return {'FINISHED'}
+
+
+# INSERT
+class Sequencer_Extra_Insert(bpy.types.Operator):
+ bl_label = 'Insert'
+ bl_idname = 'sequencerextra.insert'
+ bl_description = 'Move active strip to current frame and shift '\
+ 'forward following ones'
+ singlechannel = BoolProperty(
+ name='Single Channel',
+ default=False)
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ strip = functions.act_strip(context)
+ gap = strip.frame_final_duration
+ bpy.ops.sequencer.select_all(action='DESELECT')
+ current_frame = scn.frame_current
+
+ striplist = []
+ for i in seq.sequences:
+ try:
+ if (i.frame_final_start >= current_frame
+ and not i.mute):
+ if self.singlechannel == True:
+ if i.channel == strip.channel:
+ striplist.append(i)
+ else:
+ striplist.append(i)
+ except AttributeError:
+ pass
+ try:
+ bpy.ops.sequencerextra.selectcurrentframe('EXEC_DEFAULT',
+ mode='AFTER')
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Execution Error, '\
+ 'check your Blender version')
+ return {'CANCELLED'}
+
+ for i in range(len(striplist)):
+ str = striplist[i]
+ try:
+ if str.select == True:
+ str.frame_start += gap
+ except AttributeError:
+ pass
+ try:
+ diff = current_frame - strip.frame_final_start
+ strip.frame_start += diff
+ except AttributeError:
+ pass
+
+ strip = functions.act_strip(context)
+ scn.frame_current += strip.frame_final_duration
+ bpy.ops.sequencer.reload()
+
+ return {'FINISHED'}
+
+
+# COPY STRIP PROPERTIES
+class Sequencer_Extra_CopyProperties(bpy.types.Operator):
+ bl_label = 'Copy Properties'
+ bl_idname = 'sequencerextra.copyproperties'
+ bl_description = 'Copy properties of active strip to selected strips'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ prop = EnumProperty(
+ name='Property',
+ items=[
+ # COMMON
+ ('name', 'Name', ''),
+ ('blend_alpha', 'Opacity', ''),
+ ('blend_type', 'Blend Mode', ''),
+ ('animation_offset', 'Input - Trim Duration', ''),
+ # NON-SOUND
+ ('use_translation', 'Input - Image Offset', ''),
+ ('crop', 'Input - Image Crop', ''),
+ ('proxy', 'Proxy / Timecode', ''),
+ ('strobe', 'Filter - Strobe', ''),
+ ('color_multiply', 'Filter - Multiply', ''),
+ ('color_saturation', 'Filter - Saturation', ''),
+ ('deinterlace', 'Filter - De-Interlace', ''),
+ ('flip', 'Filter - Flip', ''),
+ ('float', 'Filter - Convert Float', ''),
+ ('alpha_mode', 'Filter - Alpha Mode', ''),
+ ('reverse', 'Filter - Backwards', ''),
+ # SOUND
+ ('pan', 'Sound - Pan', ''),
+ ('pitch', 'Sound - Pitch', ''),
+ ('volume', 'Sound - Volume', ''),
+ ('cache', 'Sound - Caching', ''),
+ # IMAGE
+ ('directory', 'Image - Directory', ''),
+ # MOVIE
+ ('mpeg_preseek', 'Movie - MPEG Preseek', ''),
+ ('stream_index', 'Movie - Stream Index', ''),
+ # WIPE
+ ('wipe', 'Effect - Wipe', ''),
+ # TRANSFORM
+ ('transform', 'Effect - Transform', ''),
+ # COLOR
+ ('color', 'Effect - Color', ''),
+ # SPEED
+ ('speed', 'Effect - Speed', ''),
+ # MULTICAM
+ ('multicam_source', 'Effect - Multicam Source', ''),
+ # EFFECT
+ ('effect_fader', 'Effect - Effect Fader', ''),
+ ],
+ default='blend_alpha')
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ strip = functions.act_strip(context)
+ selectedstrips = context.selected_editable_sequences
+
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+
+ for i in seq.sequences:
+ if (i.select == True and not i.mute):
+ try:
+ if self.prop == 'name':
+ i.name = strip.name
+ elif self.prop == 'blend_alpha':
+ i.blend_alpha = strip.blend_alpha
+ elif self.prop == 'blend_type':
+ i.blend_type = strip.blend_type
+ elif self.prop == 'animation_offset':
+ i.animation_offset_start = strip.animation_offset_start
+ i.animation_offset_end = strip.animation_offset_end
+ elif self.prop == 'use_translation':
+ i.use_translation = strip.use_translation
+ i.transform.offset_x = strip.transform.offset_x
+ i.transform.offset_y = strip.transform.offset_y
+ elif self.prop == 'crop':
+ i.use_crop = strip.use_crop
+ i.crop.min_x = strip.crop.min_x
+ i.crop.min_y = strip.crop.min_y
+ i.crop.max_x = strip.crop.max_x
+ i.crop.max_y = strip.crop.max_y
+ elif self.prop == 'proxy':
+ i.use_proxy = strip.use_proxy
+ p = strip.proxy.use_proxy_custom_directory # pep80
+ i.proxy.use_proxy_custom_directory = p
+ i.proxy.use_proxy_custom_file = strip.proxy.use_proxy_custom_file
+ i.proxy.build_100 = strip.proxy.build_100
+ i.proxy.build_25 = strip.proxy.build_25
+ i.proxy.build_50 = strip.proxy.build_50
+ i.proxy.build_75 = strip.proxy.build_75
+ i.proxy.directory = strip.proxy.directory
+ i.proxy.filepath = strip.proxy.filepath
+ i.proxy.quality = strip.proxy.quality
+ i.proxy.timecode = strip.proxy.timecode
+ i.proxy.use_overwrite = strip.proxy.use_overwrite
+ elif self.prop == 'strobe':
+ i.strobe = strip.strobe
+ elif self.prop == 'color_multiply':
+ i.color_multiply = strip.color_multiply
+ elif self.prop == 'color_saturation':
+ i.color_saturation = strip.color_saturation
+ elif self.prop == 'deinterlace':
+ i.use_deinterlace = strip.use_deinterlace
+ elif self.prop == 'flip':
+ i.use_flip_x = strip.use_flip_x
+ i.use_flip_y = strip.use_flip_y
+ elif self.prop == 'float':
+ i.use_float = strip.use_float
+ elif self.prop == 'alpha_mode':
+ i.alpha_mode = strip.alpha_mode
+ elif self.prop == 'reverse':
+ i.use_reverse_frames = strip.use_reverse_frames
+ elif self.prop == 'pan':
+ i.pan = strip.pan
+ elif self.prop == 'pitch':
+ i.pitch = strip.pitch
+ elif self.prop == 'volume':
+ i.volume = strip.volume
+ elif self.prop == 'cache':
+ i.use_memory_cache = strip.use_memory_cache
+ elif self.prop == 'directory':
+ i.directory = strip.directory
+ elif self.prop == 'mpeg_preseek':
+ i.mpeg_preseek = strip.mpeg_preseek
+ elif self.prop == 'stream_index':
+ i.stream_index = strip.stream_index
+ elif self.prop == 'wipe':
+ i.angle = strip.angle
+ i.blur_width = strip.blur_width
+ i.direction = strip.direction
+ i.transition_type = strip.transition_type
+ elif self.prop == 'transform':
+ i.interpolation = strip.interpolation
+ i.rotation_start = strip.rotation_start
+ i.use_uniform_scale = strip.use_uniform_scale
+ i.scale_start_x = strip.scale_start_x
+ i.scale_start_y = strip.scale_start_y
+ i.translation_unit = strip.translation_unit
+ i.translate_start_x = strip.translate_start_x
+ i.translate_start_y = strip.translate_start_y
+ elif self.prop == 'color':
+ i.color = strip.color
+ elif self.prop == 'speed':
+ i.use_default_fade = strip.use_default_fade
+ i.speed_factor = strip.speed_factor
+ i.use_as_speed = strip.use_as_speed
+ i.scale_to_length = strip.scale_to_length
+ i.multiply_speed = strip.multiply_speed
+ i.use_frame_blend = strip.use_frame_blend
+ elif self.prop == 'multicam_source':
+ i.multicam_source = strip.multicam_source
+ elif self.prop == 'effect_fader':
+ i.use_default_fade = strip.use_default_fade
+ i.effect_fader = strip.effect_fader
+ except:
+ pass
+
+ bpy.ops.sequencer.reload()
+ return {'FINISHED'}
+
+
+# FADE IN AND OUT
+class Sequencer_Extra_FadeInOut(bpy.types.Operator):
+ bl_idname = 'sequencerextra.fadeinout'
+ bl_label = 'Fade...'
+ bl_description = 'Fade volume or opacity of active strip'
+ mode = EnumProperty(
+ name='Direction',
+ items=(
+ ('IN', 'Fade In...', ''),
+ ('OUT', 'Fade Out...', ''),
+ ('INOUT', 'Fade In and Out...', '')),
+ default='IN',
+ )
+ bl_options = {'REGISTER', 'UNDO'}
+
+ fade_duration = IntProperty(
+ name='Duration',
+ description='Number of frames to fade',
+ min=1, max=250,
+ default=25)
+ fade_amount = FloatProperty(
+ name='Amount',
+ description='Maximum value of fade',
+ min=0.0,
+ max=100.0,
+ default=1.0)
+
+ @classmethod
+ def poll(cls, context):
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ seq = context.scene.sequence_editor
+ scn = context.scene
+ strip = seq.active_strip
+ tmp_current_frame = context.scene.frame_current
+
+ if strip.type == 'SOUND':
+ if(self.mode) == 'OUT':
+ scn.frame_current = strip.frame_final_end - self.fade_duration
+ strip.volume = self.fade_amount
+ strip.keyframe_insert('volume')
+ scn.frame_current = strip.frame_final_end
+ strip.volume = 0
+ strip.keyframe_insert('volume')
+ elif(self.mode) == 'INOUT':
+ scn.frame_current = strip.frame_final_start
+ strip.volume = 0
+ strip.keyframe_insert('volume')
+ scn.frame_current += self.fade_duration
+ strip.volume = self.fade_amount
+ strip.keyframe_insert('volume')
+ scn.frame_current = strip.frame_final_end - self.fade_duration
+ strip.volume = self.fade_amount
+ strip.keyframe_insert('volume')
+ scn.frame_current = strip.frame_final_end
+ strip.volume = 0
+ strip.keyframe_insert('volume')
+ else:
+ scn.frame_current = strip.frame_final_start
+ strip.volume = 0
+ strip.keyframe_insert('volume')
+ scn.frame_current += self.fade_duration
+ strip.volume = self.fade_amount
+ strip.keyframe_insert('volume')
+
+ else:
+ if(self.mode) == 'OUT':
+ scn.frame_current = strip.frame_final_end - self.fade_duration
+ strip.blend_alpha = self.fade_amount
+ strip.keyframe_insert('blend_alpha')
+ scn.frame_current = strip.frame_final_end
+ strip.blend_alpha = 0
+ strip.keyframe_insert('blend_alpha')
+ elif(self.mode) == 'INOUT':
+ scn.frame_current = strip.frame_final_start
+ strip.blend_alpha = 0
+ strip.keyframe_insert('blend_alpha')
+ scn.frame_current += self.fade_duration
+ strip.blend_alpha = self.fade_amount
+ strip.keyframe_insert('blend_alpha')
+ scn.frame_current = strip.frame_final_end - self.fade_duration
+ strip.blend_alpha = self.fade_amount
+ strip.keyframe_insert('blend_alpha')
+ scn.frame_current = strip.frame_final_end
+ strip.blend_alpha = 0
+ strip.keyframe_insert('blend_alpha')
+ else:
+ scn.frame_current = strip.frame_final_start
+ strip.blend_alpha = 0
+ strip.keyframe_insert('blend_alpha')
+ scn.frame_current += self.fade_duration
+ strip.blend_alpha = self.fade_amount
+ strip.keyframe_insert('blend_alpha')
+
+ scn.frame_current = tmp_current_frame
+
+ scn.kr_default_fade_duration = self.fade_duration
+ scn.kr_default_fade_amount = self.fade_amount
+ return{'FINISHED'}
+
+ def invoke(self, context, event):
+ scn = context.scene
+ functions.initSceneProperties(context)
+ self.fade_duration = scn.kr_default_fade_duration
+ self.fade_amount = scn.kr_default_fade_amount
+ return context.window_manager.invoke_props_dialog(self)
+
+
+# EXTEND TO FILL
+class Sequencer_Extra_ExtendToFill(bpy.types.Operator):
+ bl_idname = 'sequencerextra.extendtofill'
+ bl_label = 'Extend to Fill'
+ bl_description = 'Extend active strip forward to fill adjacent space'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ strip = functions.act_strip(context)
+ chn = strip.channel
+ stf = strip.frame_final_end
+ enf = 300000
+
+ for i in seq.sequences:
+ ffs = i.frame_final_start
+ if (i.channel == chn and ffs > stf):
+ if ffs < enf:
+ enf = ffs
+ if enf == 300000 and stf < scn.frame_end:
+ enf = scn.frame_end
+
+ if enf == 300000 or enf == stf:
+ self.report({'ERROR_INVALID_INPUT'}, 'Unable to extend')
+ return {'CANCELLED'}
+ else:
+ strip.frame_final_end = enf
+
+ bpy.ops.sequencer.reload()
+ return {'FINISHED'}
+
+
+# ------------------------------
+
+
+# PLACE FROM FILE BROWSER
+class Sequencer_Extra_PlaceFromFileBrowser(bpy.types.Operator):
+ bl_label = 'Place'
+ bl_idname = 'sequencerextra.placefromfilebrowser'
+ bl_description = 'Place or insert active file from File Browser'
+ insert = BoolProperty(
+ name='Insert',
+ default=False)
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def execute(self, context):
+ scn = context.scene
+ for a in context.window.screen.areas:
+ if a.type == 'FILE_BROWSER':
+ params = a.spaces[0].params
+ break
+ try:
+ params
+ except UnboundLocalError:
+ self.report({'ERROR_INVALID_INPUT'}, 'No visible File Browser')
+ return {'CANCELLED'}
+
+ if params.filename == '':
+ self.report({'ERROR_INVALID_INPUT'}, 'No file selected')
+ return {'CANCELLED'}
+
+ path = os.path.join(params.directory, params.filename)
+ frame = context.scene.frame_current
+ strip_type = functions.detect_strip_type(params.filename)
+
+ try:
+ if strip_type == 'IMAGE':
+ image_file = []
+ filename = {"name": params.filename}
+ image_file.append(filename)
+ f_in = scn.frame_current
+ f_out = f_in + scn.render.fps - 1
+ bpy.ops.sequencer.image_strip_add(files=image_file,
+ directory=params.directory, frame_start=f_in,
+ frame_end=f_out, relative_path=False)
+ elif strip_type == 'MOVIE':
+ bpy.ops.sequencer.movie_strip_add(filepath=path,
+ frame_start=frame, relative_path=False)
+ elif strip_type == 'SOUND':
+ bpy.ops.sequencer.sound_strip_add(filepath=path,
+ frame_start=frame, relative_path=False)
+ else:
+ self.report({'ERROR_INVALID_INPUT'}, 'Invalid file format')
+ return {'CANCELLED'}
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ if self.insert == True:
+ try:
+ striplist = []
+ for i in bpy.context.selected_editable_sequences:
+ if (i.select == True and i.type == "SOUND"):
+ striplist.append(i)
+ bpy.ops.sequencerextra.insert()
+ if striplist[0]:
+ striplist[0].frame_start = frame
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Execution Error, '\
+ 'check your Blender version')
+ return {'CANCELLED'}
+ else:
+ strip = functions.act_strip(context)
+ scn.frame_current += strip.frame_final_duration
+ bpy.ops.sequencer.reload()
+
+ return {'FINISHED'}
+
+
+# ------------------------------
+
+
+# SELECT STRIPS ON SAME CHANNEL
+class Sequencer_Extra_SelectSameChannel(bpy.types.Operator):
+ bl_label = 'Select Strips on the Same Channel'
+ bl_idname = 'sequencerextra.selectsamechannel'
+ bl_description = 'Select strips on the same channel as active one'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ strip = functions.act_strip(context)
+ scn = context.scene
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return True
+ else:
+ return False
+
+ def execute(self, context):
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ bpy.ops.sequencer.select_active_side(side="LEFT")
+ bpy.ops.sequencer.select_active_side(side="RIGHT")
+
+ return {'FINISHED'}
+
+
+# CURRENT-FRAME-AWARE SELECT
+class Sequencer_Extra_SelectCurrentFrame(bpy.types.Operator):
+ bl_label = 'Current-Frame-Aware Select'
+ bl_idname = 'sequencerextra.selectcurrentframe'
+ bl_description = 'Select strips according to current frame'
+ mode = EnumProperty(
+ name='Mode',
+ items=(
+ ('BEFORE', 'Before Current Frame', ''),
+ ('AFTER', 'After Current Frame', ''),
+ ('ON', 'On Current Frame', '')),
+ default='BEFORE',
+ )
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ scn = context.scene
+ if scn and scn.sequence_editor:
+ return scn.sequence_editor.sequences
+ else:
+ return False
+
+ def execute(self, context):
+ mode = self.mode
+ scn = context.scene
+ seq = scn.sequence_editor
+ cf = scn.frame_current
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+
+ if mode == 'AFTER':
+ for i in seq.sequences:
+ try:
+ if (i.frame_final_start >= cf
+ and not i.mute):
+ i.select = True
+ except AttributeError:
+ pass
+ elif mode == 'ON':
+ for i in seq.sequences:
+ try:
+ if (i.frame_final_start <= cf
+ and i.frame_final_end > cf
+ and not i.mute):
+ i.select = True
+ except AttributeError:
+ pass
+ else:
+ for i in seq.sequences:
+ try:
+ if (i.frame_final_end < cf
+ and not i.mute):
+ i.select = True
+ except AttributeError:
+ pass
+
+ return {'FINISHED'}
+
+
+# SELECT BY TYPE
+class Sequencer_Extra_SelectAllByType(bpy.types.Operator):
+ bl_label = 'All by Type'
+ bl_idname = 'sequencerextra.select_all_by_type'
+ bl_description = 'Select all the strips of the same type'
+ type = EnumProperty(
+ name='Strip Type',
+ items=(
+ ('ACTIVE', 'Same as Active Strip', ''),
+ ('IMAGE', 'Image', ''),
+ ('META', 'Meta', ''),
+ ('SCENE', 'Scene', ''),
+ ('MOVIE', 'Movie', ''),
+ ('SOUND', 'Sound', ''),
+ ('TRANSFORM', 'Transform', ''),
+ ('COLOR', 'Color', '')),
+ default='ACTIVE',
+ )
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(self, context):
+ scn = context.scene
+ if scn and scn.sequence_editor:
+ return scn.sequence_editor.sequences
+ else:
+ return False
+
+ def execute(self, context):
+ strip_type = self.type
+ scn = context.scene
+ seq = scn.sequence_editor
+ meta_level = len(seq.meta_stack)
+ if meta_level > 0:
+ seq = seq.meta_stack[meta_level - 1]
+ active_strip = functions.act_strip(context)
+ if strip_type == 'ACTIVE':
+ if active_strip == None:
+ self.report({'ERROR_INVALID_INPUT'},
+ 'No active strip')
+ return {'CANCELLED'}
+ strip_type = active_strip.type
+
+ striplist = []
+ for i in seq.sequences:
+ try:
+ if (i.type == strip_type
+ and not i.mute):
+ striplist.append(i)
+ except AttributeError:
+ pass
+ for i in range(len(striplist)):
+ str = striplist[i]
+ try:
+ str.select = True
+ except AttributeError:
+ pass
+
+ return {'FINISHED'}
+
+
+# ------------------------------
+
+# OPEN IN MOVIE CLIP EDITOR FROM FILE BROWSER
+class Clip_Extra_OpenFromFileBrowser(bpy.types.Operator):
+ bl_label = 'Open from File Browser'
+ bl_idname = 'clipextra.openfromfilebrowser'
+ bl_description = 'Load a Movie or Image Sequence from File Browser'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ def execute(self, context):
+ for a in context.window.screen.areas:
+ if a.type == 'FILE_BROWSER':
+ params = a.spaces[0].params
+ break
+ try:
+ params
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'No visible File Browser')
+ return {'CANCELLED'}
+
+ if params.filename == '':
+ self.report({'ERROR_INVALID_INPUT'}, 'No file selected')
+ return {'CANCELLED'}
+
+ strip = functions.act_strip(context)
+ path = params.directory + params.filename
+ strip_type = functions.detect_strip_type(params.filename)
+ data_exists = False
+
+ if strip_type in ('MOVIE', 'IMAGE'):
+ for i in bpy.data.movieclips:
+ if i.filepath == path:
+ data_exists = True
+ data = i
+
+ if data_exists == False:
+ try:
+ data = bpy.data.movieclips.load(filepath=path)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+ else:
+ self.report({'ERROR_INVALID_INPUT'}, 'Invalid file format')
+ return {'CANCELLED'}
+
+ for a in context.window.screen.areas:
+ if a.type == 'CLIP_EDITOR':
+ a.spaces[0].clip = data
+
+ return {'FINISHED'}
+
+
+# OPEN IN MOVIE CLIP EDITOR FROM SEQUENCER
+class Clip_Extra_OpenActiveStrip(bpy.types.Operator):
+ bl_label = 'Open Active Strip'
+ bl_idname = 'clipextra.openactivestrip'
+ bl_description = 'Load a Movie or Image Sequence from Sequence Editor'
+ bl_options = {'REGISTER', 'UNDO'}
+
+ @classmethod
+ def poll(cls, context):
+ scn = context.scene
+ strip = functions.act_strip(context)
+ if scn and scn.sequence_editor and scn.sequence_editor.active_strip:
+ return strip.type in ('MOVIE', 'IMAGE')
+ else:
+ return False
+
+ def execute(self, context):
+ strip = functions.act_strip(context)
+ data_exists = False
+
+ if strip.type == 'MOVIE':
+ path = strip.filepath
+ elif strip.type == 'IMAGE':
+ base_dir = bpy.path.relpath(strip.directory)
+ filename = strip.elements[0].filename
+ path = base_dir + '/' + filename
+ else:
+ self.report({'ERROR_INVALID_INPUT'}, 'Invalid file format')
+ return {'CANCELLED'}
+
+ for i in bpy.data.movieclips:
+ if i.filepath == path:
+ data_exists = True
+ data = i
+ if data_exists == False:
+ try:
+ data = bpy.data.movieclips.load(filepath=path)
+ except:
+ self.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
+ return {'CANCELLED'}
+
+ for a in context.window.screen.areas:
+ if a.type == 'CLIP_EDITOR':
+ a.spaces[0].clip = data
+
+ return {'FINISHED'}
+
+
+# ------------------------------
+
+
+# JOG/SHUTTLE
+class Sequencer_Extra_JogShuttle(bpy.types.Operator):
+ bl_label = 'Jog/Shuttle'
+ bl_idname = 'sequencerextra.jogshuttle'
+ bl_description = 'Jog through current sequence'
+
+ def execute(self, context):
+ scn = context.scene
+ start_frame = scn.frame_start
+ end_frame = scn.frame_end
+ duration = end_frame - start_frame
+ diff = self.x - self.init_x
+ diff /= 5
+ diff = int(diff)
+ extended_frame = diff + (self.init_current_frame - start_frame)
+ looped_frame = extended_frame % (duration + 1)
+ target_frame = start_frame + looped_frame
+ context.scene.frame_current = target_frame
+
+ def modal(self, context, event):
+ if event.type == 'MOUSEMOVE':
+ self.x = event.mouse_x
+ self.execute(context)
+ elif event.type == 'LEFTMOUSE':
+ return {'FINISHED'}
+ elif event.type in ('RIGHTMOUSE', 'ESC'):
+ return {'CANCELLED'}
+
+ return {'RUNNING_MODAL'}
+
+ def invoke(self, context, event):
+ scn = context.scene
+ self.x = event.mouse_x
+ self.init_x = self.x
+ self.init_current_frame = scn.frame_current
+ self.execute(context)
+ context.window_manager.modal_handler_add(self)
+ return {'RUNNING_MODAL'}