1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
21 from bpy
.types
import Operator
22 from bpy
.props
import (
28 from . import functions
32 class Sequencer_Extra_FrameSkip(Operator
):
33 bl_label
= "Skip One Second"
34 bl_idname
= "screenextra.frame_skip"
35 bl_description
= "Skip through the Timeline by one-second increments"
36 bl_options
= {'REGISTER', 'UNDO'}
43 def execute(self
, context
):
44 one_second
= bpy
.context
.scene
.render
.fps
47 bpy
.ops
.screen
.frame_offset(delta
=one_second
)
53 class Sequencer_Extra_TrimTimeline(Operator
):
54 bl_label
= "Trim to Timeline Content"
55 bl_idname
= "timeextra.trimtimeline"
56 bl_description
= "Automatically set start and end frames"
57 bl_options
= {'REGISTER', 'UNDO'}
60 def poll(self
, context
):
62 if scn
and scn
.sequence_editor
:
63 return scn
.sequence_editor
.sequences
67 def execute(self
, context
):
69 seq
= scn
.sequence_editor
70 meta_level
= len(seq
.meta_stack
)
72 seq
= seq
.meta_stack
[meta_level
- 1]
76 for i
in seq
.sequences
:
78 if i
.frame_final_start
< frame_start
:
79 frame_start
= i
.frame_final_start
80 if i
.frame_final_end
> frame_end
:
81 frame_end
= i
.frame_final_end
- 1
82 except AttributeError:
85 if frame_start
!= 300000:
86 scn
.frame_start
= frame_start
87 if frame_end
!= -300000:
88 scn
.frame_end
= frame_end
90 bpy
.ops
.sequencer
.view_all()
95 # Trim timeline to selection
96 class Sequencer_Extra_TrimTimelineToSelection(Operator
):
97 bl_label
= "Trim to Selection"
98 bl_idname
= "timeextra.trimtimelinetoselection"
99 bl_description
= "Set start and end frames to selection"
100 bl_options
= {'REGISTER', 'UNDO'}
103 def poll(self
, context
):
105 if scn
and scn
.sequence_editor
:
106 return scn
.sequence_editor
.sequences
110 def execute(self
, context
):
112 seq
= scn
.sequence_editor
113 meta_level
= len(seq
.meta_stack
)
115 seq
= seq
.meta_stack
[meta_level
- 1]
119 for i
in seq
.sequences
:
121 if i
.frame_final_start
< frame_start
and i
.select
is True:
122 frame_start
= i
.frame_final_start
123 if i
.frame_final_end
> frame_end
and i
.select
is True:
124 frame_end
= i
.frame_final_end
- 1
125 except AttributeError:
128 if frame_start
!= 300000:
129 scn
.frame_start
= frame_start
130 if frame_end
!= -300000:
131 scn
.frame_end
= frame_end
133 bpy
.ops
.sequencer
.view_selected()
137 # Open image with editor and create movie clip strip
139 When a movie or image strip is selected, this operator creates a movieclip
140 or find the correspondent movieclip that already exists for this footage,
141 and add a VSE clip strip with same cuts the original strip has.
142 It can convert movie strips and image sequences, both with hard cuts or
147 class Sequencer_Extra_CreateMovieclip(Operator
):
148 bl_label
= "Create a Movieclip from selected strip"
149 bl_idname
= "sequencerextra.createmovieclip"
150 bl_description
= "Create a Movieclip strip from a MOVIE or IMAGE strip"
153 def poll(self
, context
):
154 strip
= functions
.act_strip(context
)
156 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
157 return strip
.type in ('MOVIE', 'IMAGE')
161 def execute(self
, context
):
162 strip
= functions
.act_strip(context
)
165 if strip
.type == 'MOVIE':
166 path
= strip
.filepath
169 for i
in bpy
.data
.movieclips
:
170 if i
.filepath
== path
:
174 if data_exists
is False:
176 data
= bpy
.data
.movieclips
.load(filepath
=path
)
177 newstrip
= bpy
.ops
.sequencer
.movieclip_strip_add(
178 replace_sel
=True, overlap
=False,
181 newstrip
= functions
.act_strip(context
)
182 newstrip
.frame_start
= strip
.frame_start\
183 - strip
.animation_offset_start
184 tin
= strip
.frame_offset_start
+ strip
.frame_start
185 tout
= tin
+ strip
.frame_final_duration
186 # print(newstrip.frame_start, strip.frame_start, tin, tout)
187 functions
.triminout(newstrip
, tin
, tout
)
189 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
194 newstrip
= bpy
.ops
.sequencer
.movieclip_strip_add(
195 replace_sel
=True, overlap
=False,
198 newstrip
= functions
.act_strip(context
)
199 newstrip
.frame_start
= strip
.frame_start\
200 - strip
.animation_offset_start
201 # i need to declare the strip this way in order
202 # to get triminout() working
203 clip
= bpy
.context
.scene
.sequence_editor
.sequences
[
206 # i cannot change these movie clip attributes via scripts
207 # but it works in the python console...
208 # clip.animation_offset_start = strip.animation.offset_start
209 # clip.animation_offset_end = strip.animation.offset_end
210 # clip.frame_final_duration = strip.frame_final_duration
211 tin
= strip
.frame_offset_start
+ strip
.frame_start
212 tout
= tin
+ strip
.frame_final_duration
213 # print(newstrip.frame_start, strip.frame_start, tin, tout)
214 functions
.triminout(clip
, tin
, tout
)
216 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
219 elif strip
.type == 'IMAGE':
221 base_dir
= bpy
.path
.abspath(strip
.directory
)
222 scn
.frame_current
= strip
.frame_start
- strip
.animation_offset_start
224 # searching for the first frame of the sequencer. This is mandatory
225 # for hard cutted sequence strips to be correctly converted,
226 # avoiding to create a new movie clip if not needed
227 filename
= sorted(os
.listdir(base_dir
))[0]
228 path
= os
.path
.join(base_dir
, filename
)
231 for i
in bpy
.data
.movieclips
:
232 # print(i.filepath, path)
233 if i
.filepath
== path
:
237 if data_exists
is False:
239 data
= bpy
.data
.movieclips
.load(filepath
=path
)
240 newstrip
= bpy
.ops
.sequencer
.movieclip_strip_add(
241 replace_sel
=True, overlap
=False,
244 newstrip
= functions
.act_strip(context
)
245 newstrip
.frame_start
= strip
.frame_start\
246 - strip
.animation_offset_start
247 clip
= bpy
.context
.scene
.sequence_editor
.sequences
[
250 tin
= strip
.frame_offset_start
+ strip
.frame_start
251 tout
= tin
+ strip
.frame_final_duration
252 # print(newstrip.frame_start, strip.frame_start, tin, tout)
253 functions
.triminout(clip
, tin
, tout
)
255 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
259 newstrip
= bpy
.ops
.sequencer
.movieclip_strip_add(
260 replace_sel
=True, overlap
=False,
263 newstrip
= functions
.act_strip(context
)
264 newstrip
.frame_start
= strip
.frame_start\
265 - strip
.animation_offset_start
266 # need to declare the strip this way in order
267 # to get triminout() working
268 clip
= bpy
.context
.scene
.sequence_editor
.sequences
[
271 # cannot change this attributes via scripts...
272 # but it works in the python console...
273 # clip.animation_offset_start = strip.animation.offset_start
274 # clip.animation_offset_end = strip.animation.offset_end
275 # clip.frame_final_duration = strip.frame_final_duration
276 tin
= strip
.frame_offset_start
+ strip
.frame_start
277 tout
= tin
+ strip
.frame_final_duration
278 # print(newstrip.frame_start, strip.frame_start, tin, tout)
279 functions
.triminout(clip
, tin
, tout
)
281 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
284 # show the new clip in a movie clip editor, if available.
285 if strip
.type == 'MOVIE' or 'IMAGE':
286 for a
in context
.window
.screen
.areas
:
287 if a
.type == 'CLIP_EDITOR':
288 a
.spaces
[0].clip
= data
293 # Open image with editor
294 class Sequencer_Extra_Edit(Operator
):
295 bl_label
= "Open with Editor"
296 bl_idname
= "sequencerextra.edit"
297 bl_description
= "Open with Movie Clip or Image Editor"
300 def poll(self
, context
):
301 strip
= functions
.act_strip(context
)
303 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
304 return strip
.type in ('MOVIE', 'IMAGE')
308 def execute(self
, context
):
309 strip
= functions
.act_strip(context
)
313 if strip
.type == 'MOVIE':
314 path
= strip
.filepath
316 for i
in bpy
.data
.movieclips
:
317 if i
.filepath
== path
:
321 if data_exists
is False:
323 data
= bpy
.data
.movieclips
.load(filepath
=path
)
325 self
.report({'ERROR_INVALID_INPUT'}, "Error loading file")
328 elif strip
.type == 'IMAGE':
329 base_dir
= bpy
.path
.abspath(strip
.directory
)
330 strip_elem
= strip
.strip_elem_from_frame(scn
.frame_current
)
331 elem_name
= strip_elem
.filename
332 path
= base_dir
+ elem_name
334 for i
in bpy
.data
.images
:
335 if i
.filepath
== path
:
339 if data_exists
is False:
341 data
= bpy
.data
.images
.load(filepath
=path
)
343 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
346 if strip
.type == 'MOVIE':
347 for a
in context
.window
.screen
.areas
:
348 if a
.type == 'CLIP_EDITOR':
349 a
.spaces
[0].clip
= data
350 elif strip
.type == 'IMAGE':
351 for a
in context
.window
.screen
.areas
:
352 if a
.type == 'IMAGE_EDITOR':
353 a
.spaces
[0].image
= data
358 # Open image with external editor
359 class Sequencer_Extra_EditExternally(Operator
):
360 bl_label
= "Open with External Editor"
361 bl_idname
= "sequencerextra.editexternally"
362 bl_description
= "Open with the default external image editor"
365 def poll(self
, context
):
366 strip
= functions
.act_strip(context
)
368 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
369 return strip
.type == 'IMAGE'
373 def execute(self
, context
):
374 strip
= functions
.act_strip(context
)
376 base_dir
= bpy
.path
.abspath(strip
.directory
)
377 strip_elem
= strip
.strip_elem_from_frame(scn
.frame_current
)
378 path
= base_dir
+ strip_elem
.filename
381 bpy
.ops
.image
.external_edit(filepath
=path
)
383 self
.report({'ERROR_INVALID_INPUT'},
384 "Please specify an Image Editor in Preferences > File")
390 # File name to strip name
391 class Sequencer_Extra_FileNameToStripName(Operator
):
392 bl_label
= "File Name to Selected Strips Name"
393 bl_idname
= "sequencerextra.striprename"
394 bl_description
= "Set strip name to input file name"
395 bl_options
= {'REGISTER', 'UNDO'}
398 def poll(self
, context
):
400 if scn
and scn
.sequence_editor
:
401 return scn
.sequence_editor
.sequences
405 def execute(self
, context
):
407 seq
= scn
.sequence_editor
408 meta_level
= len(seq
.meta_stack
)
410 seq
= seq
.meta_stack
[meta_level
- 1]
412 for i
in seq
.sequences
:
414 if i
.type == 'IMAGE' and not i
.mute
:
416 i
.name
= i
.elements
[0].filename
417 if (i
.type == 'SOUND' or i
.type == 'MOVIE') and not i
.mute
:
419 i
.name
= bpy
.path
.display_name_from_filepath(i
.filepath
)
420 if selection
is False:
421 self
.report({'ERROR_INVALID_INPUT'},
422 "No image or movie strip selected")
428 class Sequencer_Extra_NavigateUp(Operator
):
429 bl_label
= "Navigate Up"
430 bl_idname
= "sequencerextra.navigateup"
431 bl_description
= "Move to Parent Timeline"
434 def poll(self
, context
):
436 if context
.scene
.sequence_editor
.meta_stack
:
442 def execute(self
, context
):
443 if (functions
.act_strip(context
)):
444 strip
= functions
.act_strip(context
)
445 seq_type
= strip
.type
446 if seq_type
== 'META':
447 context
.scene
.sequence_editor
.active_strip
= None
449 bpy
.ops
.sequencer
.meta_toggle()
454 class Sequencer_Extra_RippleDelete(Operator
):
455 bl_label
= "Ripple Delete"
456 bl_idname
= "sequencerextra.rippledelete"
457 bl_description
= "Delete a strip and shift back following ones"
458 bl_options
= {'REGISTER', 'UNDO'}
461 def poll(self
, context
):
463 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
468 def execute(self
, context
):
470 seq
= scn
.sequence_editor
471 meta_level
= len(seq
.meta_stack
)
473 seq
= seq
.meta_stack
[meta_level
- 1]
474 # strip = functions.act_strip(context)
475 for strip
in context
.selected_editable_sequences
:
476 cut_frame
= strip
.frame_final_start
478 bpy
.ops
.sequencer
.select_all(action
='DESELECT')
480 bpy
.ops
.sequencer
.delete()
482 for i
in seq
.sequences
:
484 if (i
.frame_final_start
> cut_frame
and
486 if i
.frame_final_start
< next_edit
:
487 next_edit
= i
.frame_final_start
490 except AttributeError:
493 if next_edit
== 300000:
495 ripple_length
= next_edit
- cut_frame
496 for i
in range(len(striplist
)):
499 if str.frame_final_start
> cut_frame
:
500 str.frame_start
= str.frame_start
- ripple_length
501 except AttributeError:
503 bpy
.ops
.sequencer
.reload()
508 class Sequencer_Extra_RippleCut(Operator
):
509 bl_label
= "Ripple Cut"
510 bl_idname
= "sequencerextra.ripplecut"
511 bl_description
= "Move a strip to buffer and shift back following ones"
512 bl_options
= {'REGISTER', 'UNDO'}
515 def poll(self
, context
):
517 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
522 def execute(self
, context
):
524 seq
= scn
.sequence_editor
525 meta_level
= len(seq
.meta_stack
)
527 seq
= seq
.meta_stack
[meta_level
- 1]
528 strip
= functions
.act_strip(context
)
529 bpy
.ops
.sequencer
.select_all(action
='DESELECT')
531 temp_cf
= scn
.frame_current
532 scn
.frame_current
= strip
.frame_final_start
533 bpy
.ops
.sequencer
.copy()
534 scn
.frame_current
= temp_cf
536 bpy
.ops
.sequencerextra
.rippledelete()
541 class Sequencer_Extra_Insert(Operator
):
543 bl_idname
= "sequencerextra.insert"
544 bl_description
= ("Move active strip to current frame and shift "
545 "forward following ones")
546 bl_options
= {'REGISTER', 'UNDO'}
548 singlechannel
: BoolProperty(
549 name
="Single Channel",
554 def poll(self
, context
):
556 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
561 def execute(self
, context
):
563 seq
= scn
.sequence_editor
564 meta_level
= len(seq
.meta_stack
)
566 seq
= seq
.meta_stack
[meta_level
- 1]
567 strip
= functions
.act_strip(context
)
568 gap
= strip
.frame_final_duration
569 bpy
.ops
.sequencer
.select_all(action
='DESELECT')
570 current_frame
= scn
.frame_current
573 for i
in seq
.sequences
:
575 if (i
.frame_final_start
>= current_frame
and
577 if self
.singlechannel
is True:
578 if i
.channel
== strip
.channel
:
582 except AttributeError:
585 bpy
.ops
.sequencerextra
.selectcurrentframe('EXEC_DEFAULT',
588 self
.report({'ERROR_INVALID_INPUT'}, "Execution Error, "
589 "check your Blender version")
592 for i
in range(len(striplist
)):
595 if str.select
is True:
596 str.frame_start
+= gap
597 except AttributeError:
600 diff
= current_frame
- strip
.frame_final_start
601 strip
.frame_start
+= diff
602 except AttributeError:
605 strip
= functions
.act_strip(context
)
606 scn
.frame_current
+= strip
.frame_final_duration
607 bpy
.ops
.sequencer
.reload()
612 # Copy strip properties
613 class Sequencer_Extra_CopyProperties(Operator
):
614 bl_label
= "Copy Properties"
615 bl_idname
= "sequencerextra.copyproperties"
616 bl_description
= "Copy properties of active strip to selected strips"
617 bl_options
= {'REGISTER', 'UNDO'}
623 ('name', 'Name', ''),
624 ('blend_alpha', 'Opacity', ''),
625 ('blend_type', 'Blend Mode', ''),
626 ('animation_offset', 'Input - Trim Duration', ''),
628 ('use_translation', 'Input - Image Offset', ''),
629 ('crop', 'Input - Image Crop', ''),
630 ('proxy', 'Proxy / Timecode', ''),
631 ('strobe', 'Filter - Strobe', ''),
632 ('color_multiply', 'Filter - Multiply', ''),
633 ('color_saturation', 'Filter - Saturation', ''),
634 ('deinterlace', 'Filter - De-Interlace', ''),
635 ('flip', 'Filter - Flip', ''),
636 ('float', 'Filter - Convert Float', ''),
637 ('alpha_mode', 'Filter - Alpha Mode', ''),
638 ('reverse', 'Filter - Backwards', ''),
640 ('pan', 'Sound - Pan', ''),
641 ('pitch', 'Sound - Pitch', ''),
642 ('volume', 'Sound - Volume', ''),
643 ('cache', 'Sound - Caching', ''),
645 ('directory', 'Image - Directory', ''),
647 ('mpeg_preseek', 'Movie - MPEG Preseek', ''),
648 ('stream_index', 'Movie - Stream Index', ''),
650 ('wipe', 'Effect - Wipe', ''),
652 ('transform', 'Effect - Transform', ''),
654 ('color', 'Effect - Color', ''),
656 ('speed', 'Effect - Speed', ''),
658 ('multicam_source', 'Effect - Multicam Source', ''),
660 ('effect_fader', 'Effect - Effect Fader', ''),
662 default
='blend_alpha'
666 def poll(self
, context
):
668 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
673 def execute(self
, context
):
674 strip
= functions
.act_strip(context
)
677 seq
= scn
.sequence_editor
678 meta_level
= len(seq
.meta_stack
)
680 seq
= seq
.meta_stack
[meta_level
- 1]
682 for i
in seq
.sequences
:
683 if (i
.select
is True and not i
.mute
):
685 if self
.prop
== 'name':
687 elif self
.prop
== 'blend_alpha':
688 i
.blend_alpha
= strip
.blend_alpha
689 elif self
.prop
== 'blend_type':
690 i
.blend_type
= strip
.blend_type
691 elif self
.prop
== 'animation_offset':
692 i
.animation_offset_start
= strip
.animation_offset_start
693 i
.animation_offset_end
= strip
.animation_offset_end
694 elif self
.prop
== 'use_translation':
695 i
.use_translation
= strip
.use_translation
696 i
.transform
.offset_x
= strip
.transform
.offset_x
697 i
.transform
.offset_y
= strip
.transform
.offset_y
698 elif self
.prop
== 'crop':
699 i
.use_crop
= strip
.use_crop
700 i
.crop
.min_x
= strip
.crop
.min_x
701 i
.crop
.min_y
= strip
.crop
.min_y
702 i
.crop
.max_x
= strip
.crop
.max_x
703 i
.crop
.max_y
= strip
.crop
.max_y
704 elif self
.prop
== 'proxy':
705 i
.use_proxy
= strip
.use_proxy
706 p
= strip
.proxy
.use_proxy_custom_directory
# pep80
707 i
.proxy
.use_proxy_custom_directory
= p
708 i
.proxy
.use_proxy_custom_file
= strip
.proxy
.use_proxy_custom_file
709 i
.proxy
.build_100
= strip
.proxy
.build_100
710 i
.proxy
.build_25
= strip
.proxy
.build_25
711 i
.proxy
.build_50
= strip
.proxy
.build_50
712 i
.proxy
.build_75
= strip
.proxy
.build_75
713 i
.proxy
.directory
= strip
.proxy
.directory
714 i
.proxy
.filepath
= strip
.proxy
.filepath
715 i
.proxy
.quality
= strip
.proxy
.quality
716 i
.proxy
.timecode
= strip
.proxy
.timecode
717 i
.proxy
.use_overwrite
= strip
.proxy
.use_overwrite
718 elif self
.prop
== 'strobe':
719 i
.strobe
= strip
.strobe
720 elif self
.prop
== 'color_multiply':
721 i
.color_multiply
= strip
.color_multiply
722 elif self
.prop
== 'color_saturation':
723 i
.color_saturation
= strip
.color_saturation
724 elif self
.prop
== 'deinterlace':
725 i
.use_deinterlace
= strip
.use_deinterlace
726 elif self
.prop
== 'flip':
727 i
.use_flip_x
= strip
.use_flip_x
728 i
.use_flip_y
= strip
.use_flip_y
729 elif self
.prop
== 'float':
730 i
.use_float
= strip
.use_float
731 elif self
.prop
== 'alpha_mode':
732 i
.alpha_mode
= strip
.alpha_mode
733 elif self
.prop
== 'reverse':
734 i
.use_reverse_frames
= strip
.use_reverse_frames
735 elif self
.prop
== 'pan':
737 elif self
.prop
== 'pitch':
738 i
.pitch
= strip
.pitch
739 elif self
.prop
== 'volume':
740 i
.volume
= strip
.volume
741 elif self
.prop
== 'cache':
742 i
.use_memory_cache
= strip
.use_memory_cache
743 elif self
.prop
== 'directory':
744 i
.directory
= strip
.directory
745 elif self
.prop
== 'mpeg_preseek':
746 i
.mpeg_preseek
= strip
.mpeg_preseek
747 elif self
.prop
== 'stream_index':
748 i
.stream_index
= strip
.stream_index
749 elif self
.prop
== 'wipe':
750 i
.angle
= strip
.angle
751 i
.blur_width
= strip
.blur_width
752 i
.direction
= strip
.direction
753 i
.transition_type
= strip
.transition_type
754 elif self
.prop
== 'transform':
755 i
.interpolation
= strip
.interpolation
756 i
.rotation_start
= strip
.rotation_start
757 i
.use_uniform_scale
= strip
.use_uniform_scale
758 i
.scale_start_x
= strip
.scale_start_x
759 i
.scale_start_y
= strip
.scale_start_y
760 i
.translation_unit
= strip
.translation_unit
761 i
.translate_start_x
= strip
.translate_start_x
762 i
.translate_start_y
= strip
.translate_start_y
763 elif self
.prop
== 'color':
764 i
.color
= strip
.color
765 elif self
.prop
== 'speed':
766 i
.use_default_fade
= strip
.use_default_fade
767 i
.speed_factor
= strip
.speed_factor
768 i
.use_as_speed
= strip
.use_as_speed
769 i
.scale_to_length
= strip
.scale_to_length
770 i
.multiply_speed
= strip
.multiply_speed
771 i
.use_frame_blend
= strip
.use_frame_blend
772 elif self
.prop
== 'multicam_source':
773 i
.multicam_source
= strip
.multicam_source
774 elif self
.prop
== 'effect_fader':
775 i
.use_default_fade
= strip
.use_default_fade
776 i
.effect_fader
= strip
.effect_fader
780 bpy
.ops
.sequencer
.reload()
785 class Sequencer_Extra_FadeInOut(Operator
):
786 bl_idname
= "sequencerextra.fadeinout"
788 bl_description
= "Fade volume or opacity of active strip"
789 bl_options
= {'REGISTER', 'UNDO'}
794 ('IN', "Fade In...", ""),
795 ('OUT', "Fade Out...", ""),
796 ('INOUT', "Fade In and Out...", "")),
800 fade_duration
: IntProperty(
802 description
='Number of frames to fade',
805 fade_amount
: FloatProperty(
807 description
='Maximum value of fade',
813 def poll(cls
, context
):
815 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
820 def execute(self
, context
):
821 seq
= context
.scene
.sequence_editor
823 strip
= seq
.active_strip
824 tmp_current_frame
= context
.scene
.frame_current
826 if strip
.type == 'SOUND':
827 if(self
.mode
) == 'OUT':
828 scn
.frame_current
= strip
.frame_final_end
- self
.fade_duration
829 strip
.volume
= self
.fade_amount
830 strip
.keyframe_insert('volume')
831 scn
.frame_current
= strip
.frame_final_end
833 strip
.keyframe_insert('volume')
834 elif(self
.mode
) == 'INOUT':
835 scn
.frame_current
= strip
.frame_final_start
837 strip
.keyframe_insert('volume')
838 scn
.frame_current
+= self
.fade_duration
839 strip
.volume
= self
.fade_amount
840 strip
.keyframe_insert('volume')
841 scn
.frame_current
= strip
.frame_final_end
- self
.fade_duration
842 strip
.volume
= self
.fade_amount
843 strip
.keyframe_insert('volume')
844 scn
.frame_current
= strip
.frame_final_end
846 strip
.keyframe_insert('volume')
848 scn
.frame_current
= strip
.frame_final_start
850 strip
.keyframe_insert('volume')
851 scn
.frame_current
+= self
.fade_duration
852 strip
.volume
= self
.fade_amount
853 strip
.keyframe_insert('volume')
856 if(self
.mode
) == 'OUT':
857 scn
.frame_current
= strip
.frame_final_end
- self
.fade_duration
858 strip
.blend_alpha
= self
.fade_amount
859 strip
.keyframe_insert('blend_alpha')
860 scn
.frame_current
= strip
.frame_final_end
861 strip
.blend_alpha
= 0
862 strip
.keyframe_insert('blend_alpha')
863 elif(self
.mode
) == 'INOUT':
864 scn
.frame_current
= strip
.frame_final_start
865 strip
.blend_alpha
= 0
866 strip
.keyframe_insert('blend_alpha')
867 scn
.frame_current
+= self
.fade_duration
868 strip
.blend_alpha
= self
.fade_amount
869 strip
.keyframe_insert('blend_alpha')
870 scn
.frame_current
= strip
.frame_final_end
- self
.fade_duration
871 strip
.blend_alpha
= self
.fade_amount
872 strip
.keyframe_insert('blend_alpha')
873 scn
.frame_current
= strip
.frame_final_end
874 strip
.blend_alpha
= 0
875 strip
.keyframe_insert('blend_alpha')
877 scn
.frame_current
= strip
.frame_final_start
878 strip
.blend_alpha
= 0
879 strip
.keyframe_insert('blend_alpha')
880 scn
.frame_current
+= self
.fade_duration
881 strip
.blend_alpha
= self
.fade_amount
882 strip
.keyframe_insert('blend_alpha')
884 scn
.frame_current
= tmp_current_frame
886 scn
.kr_default_fade_duration
= self
.fade_duration
887 scn
.kr_default_fade_amount
= self
.fade_amount
890 def invoke(self
, context
, event
):
892 functions
.initSceneProperties(context
)
893 self
.fade_duration
= scn
.kr_default_fade_duration
894 self
.fade_amount
= scn
.kr_default_fade_amount
895 return context
.window_manager
.invoke_props_dialog(self
)
899 class Sequencer_Extra_ExtendToFill(Operator
):
900 bl_idname
= "sequencerextra.extendtofill"
901 bl_label
= "Extend to Fill"
902 bl_description
= "Extend active strip forward to fill adjacent space"
903 bl_options
= {'REGISTER', 'UNDO'}
906 def poll(cls
, context
):
908 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
913 def execute(self
, context
):
915 seq
= scn
.sequence_editor
916 meta_level
= len(seq
.meta_stack
)
918 seq
= seq
.meta_stack
[meta_level
- 1]
919 strip
= functions
.act_strip(context
)
921 stf
= strip
.frame_final_end
924 for i
in seq
.sequences
:
925 ffs
= i
.frame_final_start
926 if (i
.channel
== chn
and ffs
> stf
):
929 if enf
== 300000 and stf
< scn
.frame_end
:
932 if enf
== 300000 or enf
== stf
:
933 self
.report({'ERROR_INVALID_INPUT'}, 'Unable to extend')
936 strip
.frame_final_end
= enf
938 bpy
.ops
.sequencer
.reload()
942 # Place from file browser
943 class Sequencer_Extra_PlaceFromFileBrowser(Operator
):
945 bl_idname
= "sequencerextra.placefromfilebrowser"
946 bl_description
= "Place or insert active file from File Browser"
947 bl_options
= {'REGISTER', 'UNDO'}
949 insert
: BoolProperty(
954 def execute(self
, context
):
956 for a
in context
.window
.screen
.areas
:
957 if a
.type == 'FILE_BROWSER':
958 params
= a
.spaces
[0].params
962 except UnboundLocalError:
963 self
.report({'ERROR_INVALID_INPUT'}, 'No visible File Browser')
966 if params
.filename
== '':
967 self
.report({'ERROR_INVALID_INPUT'}, 'No file selected')
970 path
= os
.path
.join(params
.directory
, params
.filename
)
971 frame
= context
.scene
.frame_current
972 strip_type
= functions
.detect_strip_type(params
.filename
)
975 if strip_type
== 'IMAGE':
977 filename
= {"name": params
.filename
}
978 image_file
.append(filename
)
979 f_in
= scn
.frame_current
980 f_out
= f_in
+ scn
.render
.fps
- 1
981 bpy
.ops
.sequencer
.image_strip_add(files
=image_file
,
982 directory
=params
.directory
, frame_start
=f_in
,
983 frame_end
=f_out
, relative_path
=False)
984 elif strip_type
== 'MOVIE':
985 bpy
.ops
.sequencer
.movie_strip_add(filepath
=path
,
986 frame_start
=frame
, relative_path
=False)
987 elif strip_type
== 'SOUND':
988 bpy
.ops
.sequencer
.sound_strip_add(filepath
=path
,
989 frame_start
=frame
, relative_path
=False)
991 self
.report({'ERROR_INVALID_INPUT'}, 'Invalid file format')
994 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
997 if self
.insert
is True:
1000 for i
in bpy
.context
.selected_editable_sequences
:
1001 if (i
.select
is True and i
.type == "SOUND"):
1003 bpy
.ops
.sequencerextra
.insert()
1005 striplist
[0].frame_start
= frame
1007 self
.report({'ERROR_INVALID_INPUT'}, "Execution Error, "
1008 "check your Blender version")
1009 return {'CANCELLED'}
1011 strip
= functions
.act_strip(context
)
1012 scn
.frame_current
+= strip
.frame_final_duration
1013 bpy
.ops
.sequencer
.reload()
1018 # Select strips on same channel
1019 class Sequencer_Extra_SelectSameChannel(Operator
):
1020 bl_label
= "Select Strips on the Same Channel"
1021 bl_idname
= "sequencerextra.selectsamechannel"
1022 bl_description
= "Select strips on the same channel as active one"
1023 bl_options
= {'REGISTER', 'UNDO'}
1026 def poll(self
, context
):
1028 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
1033 def execute(self
, context
):
1035 seq
= scn
.sequence_editor
1036 meta_level
= len(seq
.meta_stack
)
1038 seq
= seq
.meta_stack
[meta_level
- 1]
1039 bpy
.ops
.sequencer
.select_active_side(side
="LEFT")
1040 bpy
.ops
.sequencer
.select_active_side(side
="RIGHT")
1045 # Current-frame-aware select
1046 class Sequencer_Extra_SelectCurrentFrame(Operator
):
1047 bl_label
= "Current-Frame-Aware Select"
1048 bl_idname
= "sequencerextra.selectcurrentframe"
1049 bl_description
= "Select strips according to current frame"
1050 bl_options
= {'REGISTER', 'UNDO'}
1055 ('BEFORE', 'Before Current Frame', ''),
1056 ('AFTER', 'After Current Frame', ''),
1057 ('ON', 'On Current Frame', '')),
1062 def poll(self
, context
):
1064 if scn
and scn
.sequence_editor
:
1065 return scn
.sequence_editor
.sequences
1069 def execute(self
, context
):
1072 seq
= scn
.sequence_editor
1073 cf
= scn
.frame_current
1074 meta_level
= len(seq
.meta_stack
)
1076 seq
= seq
.meta_stack
[meta_level
- 1]
1079 for i
in seq
.sequences
:
1081 if (i
.frame_final_start
>= cf
and not i
.mute
):
1083 except AttributeError:
1086 for i
in seq
.sequences
:
1088 if (i
.frame_final_start
<= cf
and
1089 i
.frame_final_end
> cf
and
1092 except AttributeError:
1095 for i
in seq
.sequences
:
1097 if (i
.frame_final_end
< cf
and not i
.mute
):
1099 except AttributeError:
1106 class Sequencer_Extra_SelectAllByType(Operator
):
1107 bl_label
= "All by Type"
1108 bl_idname
= "sequencerextra.select_all_by_type"
1109 bl_description
= "Select all the strips of the same type"
1110 bl_options
= {'REGISTER', 'UNDO'}
1115 ('ACTIVE', 'Same as Active Strip', ''),
1116 ('IMAGE', 'Image', ''),
1117 ('META', 'Meta', ''),
1118 ('SCENE', 'Scene', ''),
1119 ('MOVIE', 'Movie', ''),
1120 ('SOUND', 'Sound', ''),
1121 ('TRANSFORM', 'Transform', ''),
1122 ('COLOR', 'Color', '')),
1127 def poll(self
, context
):
1129 if scn
and scn
.sequence_editor
:
1130 return scn
.sequence_editor
.sequences
1134 def execute(self
, context
):
1135 strip_type
= self
.type
1137 seq
= scn
.sequence_editor
1138 meta_level
= len(seq
.meta_stack
)
1140 seq
= seq
.meta_stack
[meta_level
- 1]
1141 active_strip
= functions
.act_strip(context
)
1142 if strip_type
== 'ACTIVE':
1143 if active_strip
is None:
1144 self
.report({'ERROR_INVALID_INPUT'},
1146 return {'CANCELLED'}
1147 strip_type
= active_strip
.type
1150 for i
in seq
.sequences
:
1152 if (i
.type == strip_type
and not i
.mute
):
1154 except AttributeError:
1156 for i
in range(len(striplist
)):
1160 except AttributeError:
1166 # Open in movie clip editor from file browser
1167 class Clip_Extra_OpenFromFileBrowser(Operator
):
1168 bl_label
= "Open from File Browser"
1169 bl_idname
= "clipextra.openfromfilebrowser"
1170 bl_description
= "Load a Movie or Image Sequence from File Browser"
1171 bl_options
= {'REGISTER', 'UNDO'}
1173 def execute(self
, context
):
1174 for a
in context
.window
.screen
.areas
:
1175 if a
.type == 'FILE_BROWSER':
1176 params
= a
.spaces
[0].params
1181 self
.report({'ERROR_INVALID_INPUT'}, 'No visible File Browser')
1182 return {'CANCELLED'}
1184 if params
.filename
== '':
1185 self
.report({'ERROR_INVALID_INPUT'}, 'No file selected')
1186 return {'CANCELLED'}
1188 path
= params
.directory
+ params
.filename
1189 strip_type
= functions
.detect_strip_type(params
.filename
)
1192 if strip_type
in ('MOVIE', 'IMAGE'):
1193 for i
in bpy
.data
.movieclips
:
1194 if i
.filepath
== path
:
1198 if data_exists
is False:
1200 data
= bpy
.data
.movieclips
.load(filepath
=path
)
1202 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
1203 return {'CANCELLED'}
1205 self
.report({'ERROR_INVALID_INPUT'}, 'Invalid file format')
1206 return {'CANCELLED'}
1208 for a
in context
.window
.screen
.areas
:
1209 if a
.type == 'CLIP_EDITOR':
1210 a
.spaces
[0].clip
= data
1215 # Open in movie clip editor from sequencer
1216 class Clip_Extra_OpenActiveStrip(Operator
):
1217 bl_label
= "Open Active Strip"
1218 bl_idname
= "clipextra.openactivestrip"
1219 bl_description
= "Load a Movie or Image Sequence from Sequence Editor"
1220 bl_options
= {'REGISTER', 'UNDO'}
1223 def poll(cls
, context
):
1225 strip
= functions
.act_strip(context
)
1226 if scn
and scn
.sequence_editor
and scn
.sequence_editor
.active_strip
:
1227 return strip
.type in ('MOVIE', 'IMAGE')
1231 def execute(self
, context
):
1232 strip
= functions
.act_strip(context
)
1235 if strip
.type == 'MOVIE':
1236 path
= strip
.filepath
1237 elif strip
.type == 'IMAGE':
1238 base_dir
= bpy
.path
.relpath(strip
.directory
)
1239 filename
= strip
.elements
[0].filename
1240 path
= base_dir
+ '/' + filename
1242 self
.report({'ERROR_INVALID_INPUT'}, 'Invalid file format')
1243 return {'CANCELLED'}
1245 for i
in bpy
.data
.movieclips
:
1246 if i
.filepath
== path
:
1249 if data_exists
is False:
1251 data
= bpy
.data
.movieclips
.load(filepath
=path
)
1253 self
.report({'ERROR_INVALID_INPUT'}, 'Error loading file')
1254 return {'CANCELLED'}
1256 for a
in context
.window
.screen
.areas
:
1257 if a
.type == 'CLIP_EDITOR':
1258 a
.spaces
[0].clip
= data
1264 class Sequencer_Extra_JogShuttle(Operator
):
1265 bl_label
= "Jog/Shuttle"
1266 bl_idname
= "sequencerextra.jogshuttle"
1267 bl_description
= ("Jog through the current sequence\n"
1268 "Left Mouse button to confirm, Right mouse\Esc to cancel")
1270 def execute(self
, context
):
1272 start_frame
= scn
.frame_start
1273 end_frame
= scn
.frame_end
1274 duration
= end_frame
- start_frame
1275 diff
= self
.x
- self
.init_x
1278 extended_frame
= diff
+ (self
.init_current_frame
- start_frame
)
1279 looped_frame
= extended_frame
% (duration
+ 1)
1280 target_frame
= start_frame
+ looped_frame
1281 context
.scene
.frame_current
= target_frame
1283 def modal(self
, context
, event
):
1284 if event
.type == 'MOUSEMOVE':
1285 self
.x
= event
.mouse_x
1286 self
.execute(context
)
1287 elif event
.type == 'LEFTMOUSE':
1289 elif event
.type in ('RIGHTMOUSE', 'ESC'):
1290 return {'CANCELLED'}
1292 return {'RUNNING_MODAL'}
1294 def invoke(self
, context
, event
):
1296 self
.x
= event
.mouse_x
1297 self
.init_x
= self
.x
1298 self
.init_current_frame
= scn
.frame_current
1299 self
.execute(context
)
1300 context
.window_manager
.modal_handler_add(self
)
1302 return {'RUNNING_MODAL'}