2023-03-14 13:38:04 +01:00
|
|
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
|
|
|
|
import bpy
|
|
|
|
import re
|
|
|
|
|
2023-03-17 20:03:38 +01:00
|
|
|
from bpy.app.handlers import persistent
|
2023-03-14 13:38:04 +01:00
|
|
|
from pathlib import Path
|
|
|
|
from vse_toolbox.bl_utils import get_settings
|
|
|
|
|
2023-03-17 20:03:38 +01:00
|
|
|
|
2023-03-14 13:38:04 +01:00
|
|
|
def get_strips(channel=0, selected_only=False):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
|
|
|
|
if isinstance(channel, str):
|
2023-03-16 18:32:17 +01:00
|
|
|
channel = get_channel(channel)
|
2023-03-14 13:38:04 +01:00
|
|
|
|
|
|
|
strips = [s for s in scn.sequence_editor.sequences_all if s.channel==channel]
|
|
|
|
|
|
|
|
if selected_only:
|
|
|
|
strips = [s for s in strips if s.select]
|
|
|
|
|
|
|
|
return sorted(strips, key=lambda x : x.frame_final_start)
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
def get_channel(name):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
|
|
|
|
channel_id = 0
|
|
|
|
channel = scn.sequence_editor.channels.get(name)
|
|
|
|
if channel:
|
|
|
|
channel_id = scn.sequence_editor.channels.keys().index(name)
|
|
|
|
|
|
|
|
return channel_id
|
|
|
|
|
2023-03-14 13:38:04 +01:00
|
|
|
def get_shot_sequence(shot):
|
|
|
|
sequences = get_strips(channel='Sequences')
|
|
|
|
return next((s.name for s in sequences if s.frame_final_start<=shot.frame_final_start<s.frame_final_end), '')
|
|
|
|
|
|
|
|
def rename_strips(
|
|
|
|
strips, template, increment=10, start_number=0, by_sequence=False):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
|
|
project = settings.active_project
|
|
|
|
episode = settings.active_episode
|
|
|
|
|
|
|
|
previous_sequence = None
|
|
|
|
strip_number = 0
|
|
|
|
|
|
|
|
for strip in strips:
|
|
|
|
sequence = get_shot_sequence(strip)
|
|
|
|
|
|
|
|
if (by_sequence and previous_sequence and
|
|
|
|
sequence and sequence != previous_sequence):
|
|
|
|
strip_number = 0
|
|
|
|
|
|
|
|
name = template.format(
|
|
|
|
episode=episode.name,
|
|
|
|
index=strip_number*increment+start_number
|
|
|
|
)
|
|
|
|
|
|
|
|
existing_strip = scn.sequence_editor.sequences_all.get(name)
|
|
|
|
if existing_strip:
|
|
|
|
existing_strip.name = f"{name}_tmp"
|
|
|
|
|
|
|
|
print(f'Renaming {strip.name} -> {name}')
|
|
|
|
strip.name = name
|
|
|
|
|
|
|
|
previous_sequence = sequence
|
|
|
|
strip_number += 1
|
|
|
|
|
|
|
|
def set_channels():
|
|
|
|
scn = bpy.context.scene
|
|
|
|
settings = get_settings()
|
2023-03-16 18:32:17 +01:00
|
|
|
items = settings.rna_type.bl_rna.properties['channel'].enum_items
|
2023-03-14 13:38:04 +01:00
|
|
|
|
|
|
|
for i, c in enumerate(items.keys(), start=1):
|
|
|
|
scn.sequence_editor.channels[i].name = c.title()
|
|
|
|
|
|
|
|
def render_strips(strips):
|
|
|
|
for strip in strips:
|
|
|
|
print(strip.name)
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
def import_edit(filepath, adapter="cmx_3600", clean_sequencer=False):
|
2023-03-14 13:38:04 +01:00
|
|
|
import opentimelineio as otio
|
2023-03-16 18:32:17 +01:00
|
|
|
from opentimelineio.schema import (
|
|
|
|
Clip,
|
|
|
|
ExternalReference,
|
|
|
|
Gap,
|
|
|
|
ImageSequenceReference,
|
|
|
|
Stack,
|
|
|
|
Timeline,
|
|
|
|
Track,
|
|
|
|
)
|
|
|
|
|
2023-03-14 13:38:04 +01:00
|
|
|
scn = bpy.context.scene
|
|
|
|
sequences = scn.sequence_editor.sequences
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
if clean_sequencer:
|
|
|
|
movie = get_strips(channel='Movie')
|
|
|
|
audio = get_strips(channel='Audio')
|
2023-03-14 13:38:04 +01:00
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
for strip in sequences:
|
|
|
|
if strip not in (movie+audio):
|
|
|
|
sequences.remove(strip)
|
|
|
|
|
|
|
|
edl = Path(filepath)
|
2023-03-14 13:38:04 +01:00
|
|
|
try:
|
|
|
|
timeline = otio.adapters.read_from_file(
|
|
|
|
str(edl), adapter, rate=scn.render.fps, ignore_timecode_mismatch=True)
|
|
|
|
except:
|
2023-03-16 18:32:17 +01:00
|
|
|
print("[>.] read_from_file Failed. Using read_from_string method.")
|
2023-03-14 13:38:04 +01:00
|
|
|
data = edl.read_text(encoding='latin-1')
|
|
|
|
timeline = otio.adapters.read_from_string(
|
|
|
|
data, adapter, rate=scn.render.fps, ignore_timecode_mismatch=True)
|
|
|
|
|
|
|
|
scn.frame_start = (
|
|
|
|
0 if timeline.global_start_time is None else timeline.global_start_time
|
|
|
|
)
|
2023-03-16 18:32:17 +01:00
|
|
|
# scn.frame_end = otio.opentime.to_frames(timeline.duration())
|
|
|
|
for track in timeline.tracks:
|
|
|
|
for child in track.each_child(shallow_search=True):
|
|
|
|
|
|
|
|
# FIXME Exclude Gaps for now. Gaps are Transitions, Blank Spaces...
|
|
|
|
# if type(child) != Clip:
|
|
|
|
if not isinstance(child, Clip):
|
|
|
|
continue
|
|
|
|
|
|
|
|
# FIXME Exclude Audio for now
|
|
|
|
if any(child.name.endswith(ext) for ext in ('.wav', '.mp3')):
|
|
|
|
channel = get_channel('Audio')
|
|
|
|
continue
|
|
|
|
|
|
|
|
channel = get_channel('Shots')
|
2023-03-14 13:38:04 +01:00
|
|
|
frame_start = otio.opentime.to_frames(
|
|
|
|
child.range_in_parent().start_time)
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
frame_end = frame_start + otio.opentime.to_frames(
|
|
|
|
child.range_in_parent().duration)
|
|
|
|
|
2023-03-14 13:38:04 +01:00
|
|
|
try:
|
|
|
|
strip = sequences.new_effect(
|
2023-03-16 18:32:17 +01:00
|
|
|
name=child.name,
|
2023-03-14 13:38:04 +01:00
|
|
|
type='COLOR',
|
2023-03-16 18:32:17 +01:00
|
|
|
channel=channel,
|
2023-03-14 13:38:04 +01:00
|
|
|
frame_start=frame_start,
|
|
|
|
frame_end=frame_end,
|
|
|
|
)
|
2023-03-16 18:32:17 +01:00
|
|
|
strip.blend_alpha = 0.0
|
2023-03-17 20:03:38 +01:00
|
|
|
strip.select = False
|
2023-03-16 18:32:17 +01:00
|
|
|
|
2023-03-14 13:38:04 +01:00
|
|
|
except Exception as e:
|
|
|
|
print('e: ', e)
|
|
|
|
continue
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
scn.frame_end = frame_end-1
|
2023-03-14 13:38:04 +01:00
|
|
|
return timeline
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
def import_movie(filepath):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
|
|
|
|
res_x = scn.render.resolution_x
|
|
|
|
res_y = scn.render.resolution_y
|
|
|
|
|
|
|
|
strip = scn.sequence_editor.sequences.new_movie(
|
|
|
|
name=filepath.stem,
|
|
|
|
filepath=str(filepath),
|
|
|
|
channel=get_channel('Movie'),
|
|
|
|
frame_start=scn.frame_start
|
|
|
|
)
|
|
|
|
|
|
|
|
elem = strip.strip_elem_from_frame(scn.frame_current)
|
|
|
|
src_width, src_height = elem.orig_width, elem.orig_height
|
|
|
|
|
|
|
|
if src_width != res_x:
|
|
|
|
strip.transform.scale_x = (res_x / src_width)
|
|
|
|
if src_height != res_y:
|
|
|
|
strip.transform.scale_y = (res_y / src_height)
|
|
|
|
|
|
|
|
if bpy.data.is_saved:
|
|
|
|
strip.filepath = bpy.path.relpath(str(filepath))
|
|
|
|
|
|
|
|
return strip
|
|
|
|
|
|
|
|
def import_sound(filepath):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
|
|
|
|
strip = scn.sequence_editor.sequences.new_sound(
|
|
|
|
name=filepath.stem,
|
|
|
|
filepath=str(filepath),
|
|
|
|
channel=get_channel('Audio'),
|
|
|
|
frame_start=scn.frame_start
|
2023-03-14 13:38:04 +01:00
|
|
|
)
|
|
|
|
|
2023-03-16 18:32:17 +01:00
|
|
|
if bpy.data.is_saved:
|
|
|
|
strip.sound.filepath = bpy.path.relpath(str(filepath))
|
|
|
|
|
|
|
|
strip.show_waveform = True
|
2023-03-14 13:38:04 +01:00
|
|
|
return strip
|
2023-03-16 18:32:17 +01:00
|
|
|
|
|
|
|
def clean_sequencer(edit=False, movie=False, sound=False):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
sequences = []
|
|
|
|
|
|
|
|
if edit:
|
|
|
|
sequences.extend(get_strips('Shots'))
|
|
|
|
if movie:
|
|
|
|
sequences.extend(get_strips('Movie'))
|
|
|
|
if sound:
|
|
|
|
sequences.extend(get_strips('Audio'))
|
|
|
|
|
|
|
|
for sequence in sequences:
|
2023-03-17 20:03:38 +01:00
|
|
|
scn.sequence_editor.sequences.remove(sequence)
|
|
|
|
|
|
|
|
@persistent
|
|
|
|
def get_active_strip(scene):
|
|
|
|
scn = bpy.context.scene
|
|
|
|
settings = get_settings()
|
|
|
|
|
|
|
|
if settings.auto_select_strip == False:
|
|
|
|
return
|
|
|
|
|
|
|
|
screen = bpy.context.screen
|
|
|
|
|
|
|
|
bpy.ops.sequencer.select_all(action="DESELECT")
|
|
|
|
|
|
|
|
strip = None
|
|
|
|
frame_current = scn.frame_current
|
|
|
|
|
|
|
|
strips = bpy.context.sequences
|
|
|
|
strips = sorted(strips,key=lambda x: (x.channel, x.frame_final_start))
|
|
|
|
|
|
|
|
for strip in strips:
|
|
|
|
#FIXME Pas propre de mettre le channel name en dur
|
|
|
|
if strip.channel != get_channel('Shots') or 0:
|
|
|
|
continue
|
|
|
|
if (not strip.lock
|
|
|
|
and strip.frame_final_end >= frame_current
|
|
|
|
and strip.frame_final_start <= frame_current):
|
|
|
|
|
|
|
|
strip.select = True
|
|
|
|
scn.sequence_editor.active_strip = strip
|