Skip to content

Instantly share code, notes, and snippets.

@Grezzo
Last active August 20, 2017 19:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Grezzo/6a730d449fb4a38147233b3469c29fe6 to your computer and use it in GitHub Desktop.
Save Grezzo/6a730d449fb4a38147233b3469c29fe6 to your computer and use it in GitHub Desktop.
Changes paths in an fcpxml to point to transcoded media (proxy and high quality media) if it can be found.
#! /usr/bin/env python
import os
import urllib
import re
import logging
import argparse
import sys
from urlparse import urlparse, urljoin
import xml.etree.ElementTree as ET
#Given an event path, check for 'Proxy Media' or 'High Quality Media' files and return a dict of paths
def get_media_in_path(event_path, transcoded_type):
media_files = {}
transcoded_media_path = os.path.join(event_path, 'Transcoded Media', transcoded_type)
#Get a list of filenames (minus the extention) and paths and add them to the dictionary
for (dirpath, _, filenames) in os.walk(transcoded_media_path):
for filename in filenames:
#Get file name without extension
first_part = os.path.splitext(filename)[0]
#Get file path and turn it into a url
file_path = os.path.join(dirpath, filename)
file_url = urljoin('file://', urllib.quote(file_path))
#add to dict
media_files[first_part] = file_url
logging.debug('Found {} file {}'.format(transcoded_type, file_url))
return media_files
parser = argparse.ArgumentParser(description="Update fcpxml to point to 'Transcoded Media' files",
epilog="Latest version available at https://gist.github.com/Grezzo/6a730d449fb4a38147233b3469c29fe6")
parser.add_argument("input", metavar='SOURCE', help="an fcpxml file")
parser.add_argument("-o", "--output", help="name of fcpxml file to create")
parser.add_argument("-p", "--proxy", help="prioritise 'Proxy Media' (default is to priorities 'High Quality' Media)", action="store_true")
parser.add_argument("-v", "--verbose", help="print verbose logging information", action="store_true")
parser.add_argument("-d", "--debug", help="print debug logging information", action="store_true")
args = parser.parse_args()
#If output omitted, set output to input so it overwrites source
if not args.output:
args.output = args.input
#Turn on logging if specified
if args.debug:
logging.getLogger().setLevel("DEBUG")
elif args.verbose:
logging.getLogger().setLevel("INFO")
#Check that input file exists
if not os.path.isfile(args.input):
sys.exit(os.path.basename(__file__) + ": error: " + args.input + " does not exist")
#Set logging format
logging.basicConfig(format="%(levelname)s:%(message)s")
#Parse fcpxml and catch any errors
try:
tree = ET.parse(args.input)
root = tree.getroot()
except:
sys.exit(os.path.basename(__file__) + ": error: " + args.input + " cannot be parsed")
#Check if it is really an fcpxml
if root.tag != "fcpxml":
sys.exit(os.path.basename(__file__) + ": error: " + args.input + " is not an fcpxml")
#Check if destination folder exists
if not os.path.exists(os.path.dirname(args.output)):
sys.exit(os.path.basename(__file__) + ": error: " + os.path.dirname(args.output) + " does not exist")
#Get library path so we can look for transcoded media inside it
library_url = root.find('library').get('location')
library_path = urlparse(library_url).path
#Get folders inside library (probably events, though maybe not)
(_, events, _) = os.walk(library_path).next()
proxy_media_files = {}
high_quality_media_files = {}
#Add media files to dicts
for event in events:
proxy_media_files.update(get_media_in_path(os.path.join(library_path, event), 'Proxy Media'))
high_quality_media_files.update(get_media_in_path(os.path.join(library_path, event), 'High Quality Media'))
#Merge dicts, giving priority to High Quality unless arg says otherwise
if args.proxy:
transcoded_media_files = high_quality_media_files.copy()
transcoded_media_files.update(proxy_media_files)
else:
transcoded_media_files = proxy_media_files.copy()
transcoded_media_files.update(high_quality_media_files)
for asset in root.findall('resources/asset'):
#get file without extension
src = urlparse(asset.get('src')).path
filename = os.path.basename(src)
first_part = os.path.splitext(filename)[0]
#Remove last 4 chars if it ends in _001 (e.g. if it's a RED file)
if re.search('_\d{3}$', first_part):
first_part = first_part[:-4]
logging.debug('Searching for transcoded media match for {}'.format(first_part))
if (first_part in transcoded_media_files):
#Update file source path
asset.set('src', transcoded_media_files[first_part])
#Remove Bookmark because it's invalid
asset.remove(asset.find('bookmark'))
#Set text to None so element self closes
if asset.text == None or asset.text.strip() == '':
asset.text = None
logging.info('Modified {} to use transcoded media'.format(first_part))
else:
logging.info('Unable to find transcoded media match for {}'.format(first_part))
tree.write(args.output, encoding='UTF-8')
@markbirnbaum
Copy link

This looks like it solves a problem I frequently have with FCPX, but I've no idea how to use it. Can anyone give me some pointers?

Thanks!

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