bulk - entire MixerTwitch repo 2019-present
I should have done this a long time ago. Oh well, no time like the present!
This commit is contained in:
@@ -0,0 +1,365 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user