Skip to content

Instantly share code, notes, and snippets.

@tin2tin
Last active August 27, 2020 17:09
Show Gist options
  • Save tin2tin/8b61cea677eb8b7840e740d9a8b32176 to your computer and use it in GitHub Desktop.
Save tin2tin/8b61cea677eb8b7840e740d9a8b32176 to your computer and use it in GitHub Desktop.
Import Final Cut Pro X markers from fcpxml files and insert them as markers and subtitles in Blender
import bpy
'''
Project Purpose:
Extract markers and time codes from Final Cut Pro X's FCPXML 1.3 formatted files
Pass an XML element into Marker.scanForMarker(). If markers are found, they are inserted as markers and subtitles in Blender.
'''
import bpy, sys, datetime
from xml.etree.ElementTree import parse
# Converts the '64bit/32bits' timecode format into seconds
def parseFCPTimeSeconds (timeString):
vals = [float(n) for n in timeString.replace('s','').split('/')]
if 1 == len(vals):
val = vals[0]
else:
val = vals[0]/vals[1]
return val
class Marker:
def __init__(self, name, startTime):
self._name = name
self._startTime = startTime
@property
def startTime(self):
return self._startTime
@property
def name(self):
return self._name
@staticmethod
def scanForMarker(element, time=[]):
start = offset = 0
try:
start = parseFCPTimeSeconds(element.attrib['start'])
except:
pass
try:
offset = parseFCPTimeSeconds(element.attrib['offset'])
except:
pass
m = []
if 'marker' == element.tag:
m.append(Marker(element.attrib['value'], start + sum(time)))
else:
time.append(offset - start)
for el in element:
m.extend(Marker.scanForMarker(el, list(time)))
return m
def get_open_channel(scene):
"""Get a channel with nothing in it"""
channels = []
try:
for strip in scene.sequence_editor.sequences_all:
channels.append(strip.channel)
if len(channels) > 0:
return max(channels) + 1
else:
return 1
except AttributeError:
return 1
# EXAMPLE:
# Import file and convert it to a list of markers sorted by ID and start time
xmlroot = parse("C:\\Users\\User\\Documents\\Blender Scripts\\FCPXML\\fcpx_project.fcpxml").getroot()
markers = sorted(Marker.scanForMarker(xmlroot), key=lambda s: s.startTime)
#scene = context.scene
#markers_sc = scene.timeline_markers
scene = bpy.context.scene
#open_channel = get_open_channel(scene)
if not scene.sequence_editor:
scene.sequence_editor_create()
print ("RESULTING ORDERED LIST:")
for m in markers:
print ("Marker {0} with start time: {1}".format(m.name, datetime.timedelta(seconds=m.startTime)))
bpy.context.scene.timeline_markers.new(m.name, frame=int(m.startTime)*24)# Insert marker
print(str(int(m.startTime)))
#Insert subtitle
text_strip = scene.sequence_editor.sequences.new_effect(
name=m.name,
type='TEXT',
channel=get_open_channel(scene),
frame_start=int(m.startTime)*24,
frame_end=int(m.startTime)*24+300
)
text_strip.font_size = 75
text_strip.text = m.name
text_strip.use_shadow = True
text_strip.select = True
text_strip.blend_type = 'ALPHA_OVER'
#added_strips.append(text_strip)
@b4zz4
Copy link

b4zz4 commented Nov 28, 2019

I don't use facebook.
Storyboarder exports to Final Cut and I use blender. So thought it would be good to mix them (blender and storyboarder).
Maybe I should do everything in blender.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment