42d7afb087
I should have done this a long time ago. Oh well, no time like the present!
365 lines
16 KiB
Python
365 lines
16 KiB
Python
import csv
|
|
import xml.etree.ElementTree as ET
|
|
import os
|
|
import uuid # Import the uuid module
|
|
from lxml import etree # Import lxml for XML handling
|
|
from xml.dom import minidom
|
|
import msvcrt
|
|
|
|
# Function to convert timecode (HH:MM:SS:FF) to total frames based on the fps
|
|
def timecode_to_frames(timecode, fps=60):
|
|
"""Convert a timecode (HH:MM:SS:FF) to total frames based on the fps."""
|
|
try:
|
|
h, m, s, f = map(int, timecode.split(':')) # Split into hours, minutes, seconds, and frames
|
|
return (h * 3600 + m * 60 + s) * fps + f # Convert to frames
|
|
except ValueError:
|
|
print(f"Invalid timecode: {timecode}")
|
|
return 0 # Return 0 or handle error as appropriate
|
|
|
|
# Define marker colors
|
|
# pproColor keys:
|
|
# default/blank/invalid = Green
|
|
# "4281740498" # Red
|
|
# "4289825711" # Purple
|
|
# "4280578025" # Orange
|
|
# "4281049552" # Yellow
|
|
# "4294967295" # White
|
|
# "4294741314" # Blue
|
|
# "4292277273" # Turquoise
|
|
marker_colors = {
|
|
"FUNI": "4294741314", # Blue
|
|
"SEG": "4280578025", # Orange
|
|
"gamign": "4289825711", # Purple
|
|
"env": "4289825711", # Purple
|
|
"AFK": "4281049552", # Yellow
|
|
"UNAFK": "4281049552", # Yellow
|
|
"BEGIN": "4281049552", # Yellow
|
|
"END": "4281049552" # Yellow
|
|
}
|
|
|
|
# Get a list of all CSV files in the current directory
|
|
csv_files = [f for f in os.listdir('.') if f.endswith('.csv')]
|
|
|
|
for csv_file in csv_files:
|
|
print(f"Processing '{csv_file}'...")
|
|
|
|
# Extract base name for sequence name
|
|
video_base = os.path.splitext(csv_file)[0]
|
|
sequence_name = f"{video_base}"
|
|
|
|
# Function to generate the XML structure
|
|
def generate_xml(markers, duration, sequence_name):
|
|
# Create the root <xmeml> element
|
|
xmeml = ET.Element("xmeml", version="4")
|
|
|
|
# Create the <sequence> element
|
|
sequence = ET.SubElement(xmeml, "sequence", id="sequence")
|
|
# Manually add the attributes with dots
|
|
sequence.set("TL.SQAudioVisibleBase", "0")
|
|
sequence.set("TL.SQVideoVisibleBase", "0")
|
|
sequence.set("TL.SQVisibleBaseTime", "0")
|
|
sequence.set("TL.SQAVDividerPosition", "0.5")
|
|
sequence.set("TL.SQHideShyTracks", "0")
|
|
sequence.set("TL.SQHeaderWidth", "292")
|
|
sequence.set("Monitor.ProgramZoomOut", "0")
|
|
sequence.set("Monitor.ProgramZoomIn", "0")
|
|
sequence.set("TL.SQTimePerPixel", "0.19999999999999998")
|
|
sequence.set("MZ.EditLine", "0")
|
|
sequence.set("MZ.Sequence.PreviewFrameSizeHeight", "1080")
|
|
sequence.set("MZ.Sequence.PreviewFrameSizeWidth", "1920")
|
|
sequence.set("MZ.Sequence.AudioTimeDisplayFormat", "200")
|
|
sequence.set("MZ.Sequence.PreviewRenderingClassID", "1061109567")
|
|
sequence.set("MZ.Sequence.PreviewRenderingPresetCodec", "1634755439")
|
|
sequence.set("MZ.Sequence.PreviewRenderingPresetPath", "EncoderPresets/SequencePreview/795454d9-d3c2-429d-9474-923ab13b7018/QuickTime.epr")
|
|
sequence.set("MZ.Sequence.PreviewUseMaxRenderQuality", "false")
|
|
sequence.set("MZ.Sequence.PreviewUseMaxBitDepth", "false")
|
|
sequence.set("MZ.Sequence.EditingModeGUID", "795454d9-d3c2-429d-9474-923ab13b7018")
|
|
sequence.set("MZ.Sequence.VideoTimeDisplayFormat", "101")
|
|
sequence.set("MZ.WorkOutPoint", "4612930560000")
|
|
sequence.set("MZ.WorkInPoint", "0")
|
|
sequence.set("explodedTracks", "true")
|
|
|
|
# Generate a unique UUID and set it in the sequence element
|
|
uuid_val = str(uuid.uuid4()).replace('-', '') # Generate a unique UUID without dashes
|
|
ET.SubElement(sequence, "uuid").text = uuid_val
|
|
|
|
# Set the duration right after the UUID
|
|
duration_tag = ET.SubElement(sequence, "duration")
|
|
duration_tag.text = str(duration)
|
|
|
|
# Add rate (timebase and ntsc)
|
|
rate = ET.SubElement(sequence, "rate")
|
|
timebase = ET.SubElement(rate, "timebase")
|
|
timebase.text = "60"
|
|
ntsc = ET.SubElement(rate, "ntsc")
|
|
ntsc.text = "FALSE"
|
|
|
|
# Set sequence name
|
|
name = ET.SubElement(sequence, "name")
|
|
name.text = sequence_name
|
|
|
|
# Create media section
|
|
media = ET.SubElement(sequence, "media")
|
|
video = ET.SubElement(media, "video")
|
|
format_tag = ET.SubElement(video, "format")
|
|
samplecharacteristics = ET.SubElement(format_tag, "samplecharacteristics")
|
|
|
|
# Now let's add a rate and other information under samplecharacteristics (to make it meaningful)
|
|
rate = ET.SubElement(samplecharacteristics, "rate")
|
|
timebase = ET.SubElement(rate, "timebase")
|
|
timebase.text = "60"
|
|
ntsc = ET.SubElement(rate, "ntsc")
|
|
ntsc.text = "FALSE"
|
|
|
|
# Add codec information
|
|
codec = ET.SubElement(samplecharacteristics, "codec")
|
|
name = ET.SubElement(codec, "name")
|
|
name.text = "Apple ProRes 422"
|
|
appspecificdata = ET.SubElement(codec, "appspecificdata")
|
|
appname = ET.SubElement(appspecificdata, "appname")
|
|
appname.text = "Final Cut Pro"
|
|
appmanufacturer = ET.SubElement(appspecificdata, "appmanufacturer")
|
|
appmanufacturer.text = "Apple Inc."
|
|
appversion = ET.SubElement(appspecificdata, "appversion")
|
|
appversion.text = "7.0"
|
|
data = ET.SubElement(appspecificdata, "data")
|
|
qtcodec = ET.SubElement(data, "qtcodec")
|
|
codecname1 = ET.SubElement(qtcodec, "codecname")
|
|
codecname1.text = "Apple ProRes 422"
|
|
codectypename = ET.SubElement(qtcodec, "codectypename")
|
|
codectypename.text = "Apple ProRes 422"
|
|
codecname2 = ET.SubElement(qtcodec, "codecname")
|
|
codecname2.text = "Apple ProRes 422"
|
|
codectypecode = ET.SubElement(qtcodec, "codectypecode")
|
|
codectypecode.text = "apcn"
|
|
codecvendorcode = ET.SubElement(qtcodec, "codecvendorcode")
|
|
codecvendorcode.text = "appl"
|
|
spatialquality = ET.SubElement(qtcodec, "spatialquality")
|
|
spatialquality.text = "1024"
|
|
temporalquality = ET.SubElement(qtcodec, "temporalquality")
|
|
temporalquality.text = "0"
|
|
keyframerate = ET.SubElement(qtcodec, "keyframerate")
|
|
keyframerate.text = "0"
|
|
datarate = ET.SubElement(qtcodec, "datarate")
|
|
datarate.text = "0"
|
|
|
|
# Add dimension info
|
|
width = ET.SubElement(samplecharacteristics, "width")
|
|
width.text = "1920"
|
|
height = ET.SubElement(samplecharacteristics, "height")
|
|
height.text = "1080"
|
|
anamorphic = ET.SubElement(samplecharacteristics, "anamorphic")
|
|
anamorphic.text = "FALSE"
|
|
pixelaspectratio = ET.SubElement(samplecharacteristics, "pixelaspectratio")
|
|
pixelaspectratio.text = "square"
|
|
fielddominance = ET.SubElement(samplecharacteristics, "fielddominance")
|
|
fielddominance.text = "none"
|
|
colordepth = ET.SubElement(samplecharacteristics, "colordepth")
|
|
colordepth.text = "24"
|
|
|
|
# Create the <track> element
|
|
track = ET.SubElement(video, "track")
|
|
track.set("TL.SQTrackShy", "0")
|
|
track.set("TL.SQTrackExpandedHeight", "25")
|
|
track.set("TL.SQTrackExpanded", "0")
|
|
track.set("MZ.TrackTargeted", "0")
|
|
|
|
#Add track modifiers
|
|
enabled = ET.SubElement(track, "enabled")
|
|
enabled.text = "TRUE"
|
|
locked = ET.SubElement(track, "locked")
|
|
locked.text = "FALSE"
|
|
|
|
# Add generator item (matte)
|
|
generatoritem = ET.SubElement(track, "generatoritem", id="clipitem-1")
|
|
item_name = ET.SubElement(generatoritem, "name")
|
|
item_name.text = f"Marker Color Matte ({markers[0]['time']})"
|
|
enabled = ET.SubElement(generatoritem, "enabled")
|
|
enabled.text = "TRUE"
|
|
generatoritem_duration = ET.SubElement(generatoritem, "duration")
|
|
generatoritem_duration.text = str(duration)
|
|
rate = ET.SubElement(generatoritem, "rate")
|
|
timebase = ET.SubElement(rate, "timebase")
|
|
timebase.text = "60"
|
|
ntsc = ET.SubElement(rate, "ntsc")
|
|
ntsc.text = "FALSE"
|
|
start = ET.SubElement(generatoritem, "start")
|
|
start.text = "0"
|
|
end = ET.SubElement(generatoritem, "end")
|
|
end.text = str(duration)
|
|
in_time = ET.SubElement(generatoritem, "in")
|
|
in_time.text = "0"
|
|
out_time = ET.SubElement(generatoritem, "out")
|
|
out_time.text = str(duration)
|
|
alphatype = ET.SubElement(generatoritem, "alphatype")
|
|
alphatype.text = "none"
|
|
effect = ET.SubElement(generatoritem, "effect")
|
|
effect_name = ET.SubElement(effect, "name")
|
|
effect_name.text = "Color"
|
|
effectid = ET.SubElement(effect, "effectid")
|
|
effectid.text = "Color"
|
|
effectcategory = ET.SubElement(effect, "effectcategory")
|
|
effectcategory.text = "Matte"
|
|
effecttype = ET.SubElement(effect, "effecttype")
|
|
effecttype.text = "generator"
|
|
mediatype = ET.SubElement(effect, "mediatype")
|
|
mediatype.text = "video"
|
|
parameter = ET.SubElement(effect, "parameter", authoringApp="PremierePro")
|
|
parameterid = ET.SubElement(parameter, "parameterid")
|
|
parameterid.text = "fillcolor"
|
|
param_name = ET.SubElement(parameter, "name")
|
|
param_name.text = "Color"
|
|
value = ET.SubElement(parameter, "value")
|
|
alpha = ET.SubElement(value, "alpha")
|
|
alpha.text = "0"
|
|
red = ET.SubElement(value, "red")
|
|
red.text = "0"
|
|
green = ET.SubElement(value, "green")
|
|
green.text = "0"
|
|
blue = ET.SubElement(value, "blue")
|
|
blue.text = "0"
|
|
filter_tag = ET.SubElement(generatoritem, "filter")
|
|
filter_effect = ET.SubElement(filter_tag, "effect")
|
|
filter_effect_name = ET.SubElement(filter_effect, "name")
|
|
filter_effect_name.text = "Opacity"
|
|
filter_effectid = ET.SubElement(filter_effect, "effectid")
|
|
filter_effectid.text = "opacity"
|
|
filter_effectcategory = ET.SubElement(filter_effect, "effectcategory")
|
|
filter_effectcategory.text = "motion"
|
|
filter_effecttype = ET.SubElement(filter_effect, "effecttype")
|
|
filter_effecttype.text = "motion"
|
|
filter_mediatype = ET.SubElement(filter_effect, "mediatype")
|
|
filter_mediatype.text = "video"
|
|
pproBypass = ET.SubElement(filter_effect, "pproBypass")
|
|
pproBypass.text = "false"
|
|
filter_parameter = ET.SubElement(filter_effect, "parameter", authoringApp="PremierePro")
|
|
filter_parameterid = ET.SubElement(filter_parameter, "parameterid")
|
|
filter_parameterid.text = "opacity"
|
|
filter_param_name = ET.SubElement(filter_parameter, "name")
|
|
filter_param_name.text = "opacity"
|
|
filter_valuemin = ET.SubElement(filter_parameter, "valuemin")
|
|
filter_valuemin.text = "0"
|
|
filter_valuemax = ET.SubElement(filter_parameter, "valuemax")
|
|
filter_valuemax.text = "100"
|
|
filter_value = ET.SubElement(filter_parameter, "value")
|
|
filter_value.text = "0"
|
|
|
|
# Create the <audio> element and its children
|
|
audio = ET.SubElement(media, "audio")
|
|
ET.SubElement(audio, "numOutputChannels").text = "2"
|
|
format_elem = ET.SubElement(audio, "format")
|
|
samplecharacteristics = ET.SubElement(format_elem, "samplecharacteristics")
|
|
ET.SubElement(samplecharacteristics, "depth").text = "16"
|
|
ET.SubElement(samplecharacteristics, "samplerate").text = "48000"
|
|
outputs = ET.SubElement(audio, "outputs")
|
|
for i in range(1, 3):
|
|
group = ET.SubElement(outputs, "groups")
|
|
ET.SubElement(group, "index").text = str(i)
|
|
ET.SubElement(group, "numchannels").text = "1"
|
|
ET.SubElement(group, "downmix").text = "0"
|
|
channel = ET.SubElement(group, "channel")
|
|
ET.SubElement(channel, "index").text = str(i)
|
|
for i in range(1, 9):
|
|
track = ET.SubElement(audio, "track")
|
|
track.set("TL.SQTrackAudioKeyframeStyle", "0")
|
|
track.set("TL.SQTrackShy", "0")
|
|
track.set("TL.SQTrackExpandedHeight", "25")
|
|
track.set("TL.SQTrackExpanded", "0")
|
|
track.set("MZ.TrackTargeted", "1")
|
|
track.set("PannerCurrentValue", "0.5")
|
|
track.set("PannerIsInverted", "true")
|
|
track.set("PannerStartKeyframe", "-91445760000000000,0.5,0,0,0,0,0,0")
|
|
track.set("PannerName", "Balance")
|
|
track.set("currentExplodedTrackIndex", "0")
|
|
track.set("totalExplodedTrackCount", "2")
|
|
track.set("premiereTrackType", "Stereo")
|
|
ET.SubElement(track, "enabled").text = "TRUE"
|
|
ET.SubElement(track, "locked").text = "FALSE"
|
|
ET.SubElement(track, "outputchannelindex").text = str((i-1) % 2 + 1)
|
|
|
|
# Create the timecode section under sequence
|
|
timecode = ET.SubElement(sequence, "timecode")
|
|
rate = ET.SubElement(timecode, "rate")
|
|
ET.SubElement(rate, "timebase").text = "60"
|
|
ET.SubElement(rate, "ntsc").text = "FALSE"
|
|
ET.SubElement(timecode, "string").text = "00:00:00:00"
|
|
ET.SubElement(timecode, "frame").text = "0"
|
|
ET.SubElement(timecode, "displayformat").text = "NDF"
|
|
|
|
# Create the labels section under sequence
|
|
labels = ET.SubElement(sequence, "labels")
|
|
ET.SubElement(labels, "label2").text = "Iris"
|
|
|
|
# Create the logginginfo section under sequence
|
|
logginginfo = ET.SubElement(sequence, "logginginfo")
|
|
ET.SubElement(logginginfo, "description")
|
|
ET.SubElement(logginginfo, "scene")
|
|
ET.SubElement(logginginfo, "shottake")
|
|
ET.SubElement(logginginfo, "lognote")
|
|
ET.SubElement(logginginfo, "good")
|
|
ET.SubElement(logginginfo, "originalvideofilename")
|
|
ET.SubElement(logginginfo, "originalaudiofilename")
|
|
|
|
# Add markers again but under sequence
|
|
for marker in markers:
|
|
marker_element = ET.SubElement(sequence, "marker")
|
|
ET.SubElement(marker_element, "comment")
|
|
ET.SubElement(marker_element, "name").text = marker['name']
|
|
# Set the in and out time as the frame count
|
|
in_frame = str(timecode_to_frames(marker['time']))
|
|
ET.SubElement(marker_element, "in").text = in_frame
|
|
ET.SubElement(marker_element, "out").text = "-1"
|
|
# Set color based on marker name
|
|
color_code = marker_colors.get(marker['name'])
|
|
if color_code:
|
|
ppro_color = ET.SubElement(marker_element, "pproColor")
|
|
ppro_color.text = color_code
|
|
print(f"Set color for marker '{marker['name']}' to '{color_code}'")
|
|
else:
|
|
print(f"Default color (Green) used for marker '{marker['name']}'")
|
|
|
|
# Create the labels section under sequence
|
|
labels = ET.SubElement(sequence, "labels")
|
|
ET.SubElement(labels, "label2").text = "Forest"
|
|
|
|
# Write to XML file
|
|
output_file = csv_file.replace('.csv', '.xml')
|
|
tree = ET.ElementTree(xmeml)
|
|
tree.write(output_file, encoding="UTF-8", xml_declaration=True)
|
|
|
|
print(f"XML file '{output_file}' has been created successfully.")
|
|
|
|
|
|
# Read the CSV file and process the data
|
|
markers = [] # List to store markers
|
|
|
|
with open(csv_file, newline='', encoding='utf-8') as csvfile:
|
|
csv_reader = csv.DictReader(csvfile, delimiter='\t')
|
|
marker_count = 0
|
|
|
|
for row in csv_reader:
|
|
marker_name = row['Marker Name']
|
|
in_point = row['In']
|
|
out_point = row['Out']
|
|
|
|
print(f"Adding marker: Name='{marker_name}', In='{in_point}', Out='{out_point}'")
|
|
|
|
# Add marker to list
|
|
markers.append({'name': marker_name, 'time': in_point})
|
|
marker_count += 1
|
|
|
|
print(f"Total markers added for '{csv_file}': {marker_count}")
|
|
|
|
# Calculate the duration using the final marker's timecode
|
|
final_marker = markers[-1] if markers else None
|
|
duration = 0
|
|
if final_marker:
|
|
duration = timecode_to_frames(final_marker['time'], fps=60)
|
|
|
|
generate_xml(markers, duration, sequence_name) # Pass sequence_name
|
|
|
|
print("------------------------------------------------------------")
|
|
|
|
print("All files have been processed.")
|
|
print("Press any key to exit...")
|
|
msvcrt.getch() |