mirror of
https://github.com/ynput/ayon-core.git
synced 2026-01-01 08:24:53 +01:00
flame: fixing OpenClipSolver
This commit is contained in:
parent
06d2e89865
commit
a103eba505
4 changed files with 56 additions and 603 deletions
|
|
@ -784,9 +784,14 @@ class MediaInfoFile(object):
|
||||||
# get clip data and make them single if there is multiple
|
# get clip data and make them single if there is multiple
|
||||||
# clips data
|
# clips data
|
||||||
xml_data = self._make_single_clip_media_info(tmp_path)
|
xml_data = self._make_single_clip_media_info(tmp_path)
|
||||||
|
self.log.debug("xml_data: {}".format(xml_data))
|
||||||
|
self.log.debug("type: {}".format(type(xml_data)))
|
||||||
|
|
||||||
# get all time related data and assign them
|
# get all time related data and assign them
|
||||||
self._get_time_info_from_origin(xml_data)
|
self._get_time_info_from_origin(xml_data)
|
||||||
|
self.log.debug("start_frame: {}".format(self.start_frame))
|
||||||
|
self.log.debug("fps: {}".format(self.fps))
|
||||||
|
self.log.debug("drop frame: {}".format(self.drop_mode))
|
||||||
self.clip_data = xml_data
|
self.clip_data = xml_data
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -913,10 +918,19 @@ class MediaInfoFile(object):
|
||||||
self.log.warning(msg)
|
self.log.warning(msg)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def write_clip_data_to_file(fpath, xml_data):
|
def write_clip_data_to_file(fpath, xml_element_data):
|
||||||
|
""" Write xml element of clip data to file
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fpath (string): file path
|
||||||
|
xml_element_data (xml.etree.ElementTree.Element): xml data
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
IOError: If data could not be written to file
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
# save it as new file
|
# save it as new file
|
||||||
tree = cET.ElementTree(xml_data)
|
tree = cET.ElementTree(xml_element_data)
|
||||||
tree.write(
|
tree.write(
|
||||||
fpath, xml_declaration=True,
|
fpath, xml_declaration=True,
|
||||||
method='xml', encoding='UTF-8'
|
method='xml', encoding='UTF-8'
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,11 @@
|
||||||
import itertools
|
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
|
||||||
import xml.etree.cElementTree as cET
|
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
from xml.etree import ElementTree as ET
|
from xml.etree import ElementTree as ET
|
||||||
|
|
||||||
import openpype.api as openpype
|
import openpype.api as openpype
|
||||||
import qargparse
|
import qargparse
|
||||||
import six
|
|
||||||
from openpype import style
|
from openpype import style
|
||||||
from openpype.pipeline import LegacyCreator, LoaderPlugin
|
from openpype.pipeline import LegacyCreator, LoaderPlugin
|
||||||
from Qt import QtCore, QtWidgets
|
from Qt import QtCore, QtWidgets
|
||||||
|
|
@ -658,8 +654,8 @@ class PublishableClip:
|
||||||
|
|
||||||
|
|
||||||
# Publishing plugin functions
|
# Publishing plugin functions
|
||||||
# Loader plugin functions
|
|
||||||
|
|
||||||
|
# Loader plugin functions
|
||||||
class ClipLoader(LoaderPlugin):
|
class ClipLoader(LoaderPlugin):
|
||||||
"""A basic clip loader for Flame
|
"""A basic clip loader for Flame
|
||||||
|
|
||||||
|
|
@ -679,53 +675,37 @@ class ClipLoader(LoaderPlugin):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# TODO: inheritance from flame.api.lib.MediaInfoFile
|
class OpenClipSolver(flib.MediaInfoFile):
|
||||||
class OpenClipSolver:
|
|
||||||
media_script_path = "/opt/Autodesk/mio/current/dl_get_media_info"
|
|
||||||
tmp_name = "_tmp.clip"
|
|
||||||
tmp_file = None
|
|
||||||
create_new_clip = False
|
create_new_clip = False
|
||||||
|
|
||||||
out_feed_nb_ticks = None
|
|
||||||
out_feed_fps = None
|
|
||||||
out_feed_drop_mode = None
|
|
||||||
|
|
||||||
log = log
|
log = log
|
||||||
|
|
||||||
def __init__(self, openclip_file_path, feed_data):
|
def __init__(self, openclip_file_path, feed_data):
|
||||||
# test if media script paht exists
|
self.out_file = openclip_file_path
|
||||||
self._validate_media_script_path()
|
|
||||||
|
|
||||||
# new feed variables:
|
# new feed variables:
|
||||||
feed_path = feed_data["path"]
|
feed_path = feed_data.pop("path")
|
||||||
|
|
||||||
|
# initialize parent class
|
||||||
|
super(OpenClipSolver, self).__init__(
|
||||||
|
feed_path,
|
||||||
|
**feed_data
|
||||||
|
)
|
||||||
|
|
||||||
|
# get other metadata
|
||||||
self.feed_version_name = feed_data["version"]
|
self.feed_version_name = feed_data["version"]
|
||||||
self.feed_colorspace = feed_data.get("colorspace")
|
self.feed_colorspace = feed_data.get("colorspace")
|
||||||
|
self.log.debug("feed_version_name: {}".format(self.feed_version_name))
|
||||||
if feed_data.get("logger"):
|
|
||||||
self.log = feed_data["logger"]
|
|
||||||
|
|
||||||
# derivate other feed variables
|
# derivate other feed variables
|
||||||
self.feed_basename = os.path.basename(feed_path)
|
self.feed_basename = os.path.basename(feed_path)
|
||||||
self.feed_dir = os.path.dirname(feed_path)
|
self.feed_dir = os.path.dirname(feed_path)
|
||||||
self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower()
|
self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower()
|
||||||
|
self.log.debug("feed_ext: {}".format(self.feed_ext))
|
||||||
if not self._is_valid_tmp_file(openclip_file_path):
|
self.log.debug("out_file: {}".format(self.out_file))
|
||||||
# openclip does not exist yet and will be created
|
if not self._is_valid_tmp_file(self.out_file):
|
||||||
self.tmp_file = self.out_file = openclip_file_path
|
|
||||||
self.create_new_clip = True
|
self.create_new_clip = True
|
||||||
|
|
||||||
else:
|
|
||||||
# update already created clip
|
|
||||||
# output a temp file
|
|
||||||
self.out_file = openclip_file_path
|
|
||||||
self.tmp_file = os.path.join(self.feed_dir, self.tmp_name)
|
|
||||||
|
|
||||||
# remove previously generated temp files
|
|
||||||
# it will be regenerated
|
|
||||||
self._clear_tmp_file()
|
|
||||||
|
|
||||||
self.log.info("Temp File: {}".format(self.tmp_file))
|
|
||||||
|
|
||||||
def _is_valid_tmp_file(self, file):
|
def _is_valid_tmp_file(self, file):
|
||||||
# check if file exists
|
# check if file exists
|
||||||
if os.path.isfile(file):
|
if os.path.isfile(file):
|
||||||
|
|
@ -740,7 +720,6 @@ class OpenClipSolver:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def make(self):
|
def make(self):
|
||||||
self._generate_media_info_file()
|
|
||||||
|
|
||||||
if self.create_new_clip:
|
if self.create_new_clip:
|
||||||
# New openClip
|
# New openClip
|
||||||
|
|
@ -748,69 +727,17 @@ class OpenClipSolver:
|
||||||
else:
|
else:
|
||||||
self._update_open_clip()
|
self._update_open_clip()
|
||||||
|
|
||||||
def _validate_media_script_path(self):
|
|
||||||
if not os.path.isfile(self.media_script_path):
|
|
||||||
raise IOError("Media Scirpt does not exist: `{}`".format(
|
|
||||||
self.media_script_path))
|
|
||||||
|
|
||||||
def _generate_media_info_file(self):
|
|
||||||
# Create cmd arguments for gettig xml file info file
|
|
||||||
cmd_args = [
|
|
||||||
self.media_script_path,
|
|
||||||
"-e", self.feed_ext,
|
|
||||||
"-o", self.tmp_file,
|
|
||||||
self.feed_dir
|
|
||||||
]
|
|
||||||
|
|
||||||
# execute creation of clip xml template data
|
|
||||||
try:
|
|
||||||
openpype.run_subprocess(cmd_args)
|
|
||||||
self._make_single_clip_media_info()
|
|
||||||
except TypeError:
|
|
||||||
self.log.error("Error creating self.tmp_file")
|
|
||||||
six.reraise(*sys.exc_info())
|
|
||||||
|
|
||||||
def _make_single_clip_media_info(self):
|
|
||||||
with open(self.tmp_file) as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
_added_root = itertools.chain(
|
|
||||||
"<root>", deepcopy(lines)[1:], "</root>")
|
|
||||||
new_root = ET.fromstringlist(_added_root)
|
|
||||||
|
|
||||||
# find the clip which is matching to my input name
|
|
||||||
xml_clips = new_root.findall("clip")
|
|
||||||
matching_clip = None
|
|
||||||
for xml_clip in xml_clips:
|
|
||||||
if xml_clip.find("name").text in self.feed_basename:
|
|
||||||
matching_clip = xml_clip
|
|
||||||
|
|
||||||
if matching_clip is None:
|
|
||||||
# return warning there is missing clip
|
|
||||||
raise ET.ParseError(
|
|
||||||
"Missing clip in `{}`. Available clips {}".format(
|
|
||||||
self.feed_basename, [
|
|
||||||
xml_clip.find("name").text
|
|
||||||
for xml_clip in xml_clips
|
|
||||||
]
|
|
||||||
))
|
|
||||||
|
|
||||||
self._write_result_xml_to_file(self.tmp_file, matching_clip)
|
|
||||||
|
|
||||||
def _clear_tmp_file(self):
|
|
||||||
if os.path.isfile(self.tmp_file):
|
|
||||||
os.remove(self.tmp_file)
|
|
||||||
|
|
||||||
def _clear_handler(self, xml_object):
|
def _clear_handler(self, xml_object):
|
||||||
for handler in xml_object.findall("./handler"):
|
for handler in xml_object.findall("./handler"):
|
||||||
self.log.debug("Handler found")
|
self.log.info("Handler found")
|
||||||
xml_object.remove(handler)
|
xml_object.remove(handler)
|
||||||
|
|
||||||
def _create_new_open_clip(self):
|
def _create_new_open_clip(self):
|
||||||
self.log.info("Building new openClip")
|
self.log.info("Building new openClip")
|
||||||
|
self.log.debug(">> self.clip_data: {}".format(self.clip_data))
|
||||||
|
|
||||||
tmp_xml = ET.parse(self.tmp_file)
|
# clip data comming from MediaInfoFile
|
||||||
|
tmp_xml_feeds = self.clip_data.find('tracks/track/feeds')
|
||||||
tmp_xml_feeds = tmp_xml.find('tracks/track/feeds')
|
|
||||||
tmp_xml_feeds.set('currentVersion', self.feed_version_name)
|
tmp_xml_feeds.set('currentVersion', self.feed_version_name)
|
||||||
for tmp_feed in tmp_xml_feeds:
|
for tmp_feed in tmp_xml_feeds:
|
||||||
tmp_feed.set('vuid', self.feed_version_name)
|
tmp_feed.set('vuid', self.feed_version_name)
|
||||||
|
|
@ -821,46 +748,48 @@ class OpenClipSolver:
|
||||||
|
|
||||||
self._clear_handler(tmp_feed)
|
self._clear_handler(tmp_feed)
|
||||||
|
|
||||||
tmp_xml_versions_obj = tmp_xml.find('versions')
|
tmp_xml_versions_obj = self.clip_data.find('versions')
|
||||||
tmp_xml_versions_obj.set('currentVersion', self.feed_version_name)
|
tmp_xml_versions_obj.set('currentVersion', self.feed_version_name)
|
||||||
for xml_new_version in tmp_xml_versions_obj:
|
for xml_new_version in tmp_xml_versions_obj:
|
||||||
xml_new_version.set('uid', self.feed_version_name)
|
xml_new_version.set('uid', self.feed_version_name)
|
||||||
xml_new_version.set('type', 'version')
|
xml_new_version.set('type', 'version')
|
||||||
|
|
||||||
xml_data = self._fix_xml_data(tmp_xml)
|
self._clear_handler(self.clip_data)
|
||||||
self.log.info("Adding feed version: {}".format(self.feed_basename))
|
self.log.info("Adding feed version: {}".format(self.feed_basename))
|
||||||
|
|
||||||
self._write_result_xml_to_file(self.out_file, xml_data)
|
self.write_clip_data_to_file(self.out_file, self.clip_data)
|
||||||
|
|
||||||
self.log.info("openClip Updated: {}".format(self.tmp_file))
|
|
||||||
|
|
||||||
def _update_open_clip(self):
|
def _update_open_clip(self):
|
||||||
self.log.info("Updating openClip ..")
|
self.log.info("Updating openClip ..")
|
||||||
|
|
||||||
out_xml = ET.parse(self.out_file)
|
out_xml = ET.parse(self.out_file)
|
||||||
tmp_xml = ET.parse(self.tmp_file)
|
out_xml = out_xml.getroot()
|
||||||
|
|
||||||
self.log.debug(">> out_xml: {}".format(out_xml))
|
self.log.debug(">> out_xml: {}".format(out_xml))
|
||||||
self.log.debug(">> tmp_xml: {}".format(tmp_xml))
|
self.log.debug(">> self.clip_data: {}".format(self.clip_data))
|
||||||
|
|
||||||
# Get new feed from tmp file
|
# Get new feed from tmp file
|
||||||
tmp_xml_feed = tmp_xml.find('tracks/track/feeds/feed')
|
tmp_xml_feed = self.clip_data.find('tracks/track/feeds/feed')
|
||||||
|
|
||||||
self._clear_handler(tmp_xml_feed)
|
self._clear_handler(tmp_xml_feed)
|
||||||
self._get_time_info_from_origin(out_xml)
|
|
||||||
|
|
||||||
if self.out_feed_fps:
|
# update fps from MediaInfoFile class
|
||||||
|
if self.fps:
|
||||||
tmp_feed_fps_obj = tmp_xml_feed.find(
|
tmp_feed_fps_obj = tmp_xml_feed.find(
|
||||||
"startTimecode/rate")
|
"startTimecode/rate")
|
||||||
tmp_feed_fps_obj.text = self.out_feed_fps
|
tmp_feed_fps_obj.text = str(self.fps)
|
||||||
if self.out_feed_nb_ticks:
|
|
||||||
|
# update start_frame from MediaInfoFile class
|
||||||
|
if self.start_frame:
|
||||||
tmp_feed_nb_ticks_obj = tmp_xml_feed.find(
|
tmp_feed_nb_ticks_obj = tmp_xml_feed.find(
|
||||||
"startTimecode/nbTicks")
|
"startTimecode/nbTicks")
|
||||||
tmp_feed_nb_ticks_obj.text = self.out_feed_nb_ticks
|
tmp_feed_nb_ticks_obj.text = str(self.start_frame)
|
||||||
if self.out_feed_drop_mode:
|
|
||||||
|
# update drop_mode from MediaInfoFile class
|
||||||
|
if self.drop_mode:
|
||||||
tmp_feed_drop_mode_obj = tmp_xml_feed.find(
|
tmp_feed_drop_mode_obj = tmp_xml_feed.find(
|
||||||
"startTimecode/dropMode")
|
"startTimecode/dropMode")
|
||||||
tmp_feed_drop_mode_obj.text = self.out_feed_drop_mode
|
tmp_feed_drop_mode_obj.text = str(self.drop_mode)
|
||||||
|
|
||||||
new_path_obj = tmp_xml_feed.find(
|
new_path_obj = tmp_xml_feed.find(
|
||||||
"spans/span/path")
|
"spans/span/path")
|
||||||
|
|
@ -893,7 +822,7 @@ class OpenClipSolver:
|
||||||
"version", {"type": "version", "uid": self.feed_version_name})
|
"version", {"type": "version", "uid": self.feed_version_name})
|
||||||
out_xml_versions_obj.insert(0, new_version_obj)
|
out_xml_versions_obj.insert(0, new_version_obj)
|
||||||
|
|
||||||
xml_data = self._fix_xml_data(out_xml)
|
self._clear_handler(out_xml)
|
||||||
|
|
||||||
# fist create backup
|
# fist create backup
|
||||||
self._create_openclip_backup_file(self.out_file)
|
self._create_openclip_backup_file(self.out_file)
|
||||||
|
|
@ -901,30 +830,9 @@ class OpenClipSolver:
|
||||||
self.log.info("Adding feed version: {}".format(
|
self.log.info("Adding feed version: {}".format(
|
||||||
self.feed_version_name))
|
self.feed_version_name))
|
||||||
|
|
||||||
self._write_result_xml_to_file(self.out_file, xml_data)
|
self.write_clip_data_to_file(self.out_file, out_xml)
|
||||||
|
|
||||||
self.log.info("openClip Updated: {}".format(self.out_file))
|
self.log.debug("OpenClip Updated: {}".format(self.out_file))
|
||||||
|
|
||||||
self._clear_tmp_file()
|
|
||||||
|
|
||||||
def _get_time_info_from_origin(self, xml_data):
|
|
||||||
try:
|
|
||||||
for out_track in xml_data.iter('track'):
|
|
||||||
for out_feed in out_track.iter('feed'):
|
|
||||||
out_feed_nb_ticks_obj = out_feed.find(
|
|
||||||
'startTimecode/nbTicks')
|
|
||||||
self.out_feed_nb_ticks = out_feed_nb_ticks_obj.text
|
|
||||||
out_feed_fps_obj = out_feed.find(
|
|
||||||
'startTimecode/rate')
|
|
||||||
self.out_feed_fps = out_feed_fps_obj.text
|
|
||||||
out_feed_drop_mode_obj = out_feed.find(
|
|
||||||
'startTimecode/dropMode')
|
|
||||||
self.out_feed_drop_mode = out_feed_drop_mode_obj.text
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
except Exception as msg:
|
|
||||||
self.log.warning(msg)
|
|
||||||
|
|
||||||
def _feed_exists(self, xml_data, path):
|
def _feed_exists(self, xml_data, path):
|
||||||
# loop all available feed paths and check if
|
# loop all available feed paths and check if
|
||||||
|
|
@ -935,17 +843,6 @@ class OpenClipSolver:
|
||||||
"Not appending file as it already is in .clip file")
|
"Not appending file as it already is in .clip file")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _fix_xml_data(self, xml_data):
|
|
||||||
xml_root = xml_data.getroot()
|
|
||||||
self._clear_handler(xml_root)
|
|
||||||
return xml_root
|
|
||||||
|
|
||||||
def _write_result_xml_to_file(self, file, xml_data):
|
|
||||||
# save it as new file
|
|
||||||
tree = cET.ElementTree(xml_data)
|
|
||||||
tree.write(file, xml_declaration=True,
|
|
||||||
method='xml', encoding='UTF-8')
|
|
||||||
|
|
||||||
def _create_openclip_backup_file(self, file):
|
def _create_openclip_backup_file(self, file):
|
||||||
bck_file = "{}.bak".format(file)
|
bck_file = "{}.bak".format(file)
|
||||||
# if backup does not exist
|
# if backup does not exist
|
||||||
|
|
|
||||||
|
|
@ -1,428 +0,0 @@
|
||||||
import os
|
|
||||||
import tempfile
|
|
||||||
import itertools
|
|
||||||
import contextlib
|
|
||||||
import xml.etree.cElementTree as cET
|
|
||||||
from copy import deepcopy
|
|
||||||
import shutil
|
|
||||||
from xml.etree import ElementTree as ET
|
|
||||||
|
|
||||||
import openpype.api as openpype
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
|
||||||
def maintained_temp_file_path(suffix=None):
|
|
||||||
_suffix = suffix or ""
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Store dumped json to temporary file
|
|
||||||
temporary_file = tempfile.mktemp(
|
|
||||||
suffix=_suffix, prefix="flame_maintained_")
|
|
||||||
yield temporary_file.replace("\\", "/")
|
|
||||||
|
|
||||||
except IOError as _error:
|
|
||||||
raise IOError(
|
|
||||||
"Not able to create temp json file: {}".format(_error))
|
|
||||||
|
|
||||||
finally:
|
|
||||||
# Remove the temporary json
|
|
||||||
os.remove(temporary_file)
|
|
||||||
|
|
||||||
|
|
||||||
class MediaInfoFile(object):
|
|
||||||
"""Class to get media info file clip data
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
IOError: MEDIA_SCRIPT_PATH path doesn't exists
|
|
||||||
TypeError: Not able to generate clip xml data file
|
|
||||||
ET.ParseError: Missing clip in xml clip data
|
|
||||||
IOError: Not able to save xml clip data to file
|
|
||||||
|
|
||||||
Attributes:
|
|
||||||
str: `MEDIA_SCRIPT_PATH` path to flame binary
|
|
||||||
logging.Logger: `log` logger
|
|
||||||
|
|
||||||
TODO: add method for getting metadata to dict
|
|
||||||
"""
|
|
||||||
MEDIA_SCRIPT_PATH = "/opt/Autodesk/mio/current/dl_get_media_info"
|
|
||||||
|
|
||||||
log = log
|
|
||||||
|
|
||||||
_clip_data = None
|
|
||||||
_start_frame = None
|
|
||||||
_fps = None
|
|
||||||
_drop_mode = None
|
|
||||||
|
|
||||||
def __init__(self, path, **kwargs):
|
|
||||||
|
|
||||||
# replace log if any
|
|
||||||
if kwargs.get("logger"):
|
|
||||||
self.log = kwargs["logger"]
|
|
||||||
|
|
||||||
# test if `dl_get_media_info` paht exists
|
|
||||||
self._validate_media_script_path()
|
|
||||||
|
|
||||||
# derivate other feed variables
|
|
||||||
self.feed_basename = os.path.basename(path)
|
|
||||||
self.feed_dir = os.path.dirname(path)
|
|
||||||
self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower()
|
|
||||||
|
|
||||||
with maintained_temp_file_path(".clip") as tmp_path:
|
|
||||||
self.log.info("Temp File: {}".format(tmp_path))
|
|
||||||
self._generate_media_info_file(tmp_path)
|
|
||||||
|
|
||||||
# get clip data and make them single if there is multiple
|
|
||||||
# clips data
|
|
||||||
xml_data = self._make_single_clip_media_info(tmp_path)
|
|
||||||
self.log.info("xml_data: {}".format(xml_data))
|
|
||||||
self.log.info("type: {}".format(type(xml_data)))
|
|
||||||
|
|
||||||
# get all time related data and assign them
|
|
||||||
self._get_time_info_from_origin(xml_data)
|
|
||||||
self.log.info("start_frame: {}".format(self.start_frame))
|
|
||||||
self.log.info("fps: {}".format(self.fps))
|
|
||||||
self.log.info("drop frame: {}".format(self.drop_mode))
|
|
||||||
self.clip_data = xml_data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def clip_data(self):
|
|
||||||
"""Clip's xml clip data
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
xml.etree.ElementTree: xml data
|
|
||||||
"""
|
|
||||||
return self._clip_data
|
|
||||||
|
|
||||||
@clip_data.setter
|
|
||||||
def clip_data(self, data):
|
|
||||||
self._clip_data = data
|
|
||||||
|
|
||||||
@property
|
|
||||||
def start_frame(self):
|
|
||||||
""" Clip's starting frame found in timecode
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
int: number of frames
|
|
||||||
"""
|
|
||||||
return self._start_frame
|
|
||||||
|
|
||||||
@start_frame.setter
|
|
||||||
def start_frame(self, number):
|
|
||||||
self._start_frame = int(number)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def fps(self):
|
|
||||||
""" Clip's frame rate
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: frame rate
|
|
||||||
"""
|
|
||||||
return self._fps
|
|
||||||
|
|
||||||
@fps.setter
|
|
||||||
def fps(self, fl_number):
|
|
||||||
self._fps = float(fl_number)
|
|
||||||
|
|
||||||
@property
|
|
||||||
def drop_mode(self):
|
|
||||||
""" Clip's drop frame mode
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: drop frame flag
|
|
||||||
"""
|
|
||||||
return self._drop_mode
|
|
||||||
|
|
||||||
@drop_mode.setter
|
|
||||||
def drop_mode(self, text):
|
|
||||||
self._drop_mode = str(text)
|
|
||||||
|
|
||||||
def _validate_media_script_path(self):
|
|
||||||
if not os.path.isfile(self.MEDIA_SCRIPT_PATH):
|
|
||||||
raise IOError("Media Scirpt does not exist: `{}`".format(
|
|
||||||
self.MEDIA_SCRIPT_PATH))
|
|
||||||
|
|
||||||
def _generate_media_info_file(self, fpath):
|
|
||||||
# Create cmd arguments for gettig xml file info file
|
|
||||||
cmd_args = [
|
|
||||||
self.MEDIA_SCRIPT_PATH,
|
|
||||||
"-e", self.feed_ext,
|
|
||||||
"-o", fpath,
|
|
||||||
self.feed_dir
|
|
||||||
]
|
|
||||||
|
|
||||||
try:
|
|
||||||
# execute creation of clip xml template data
|
|
||||||
openpype.run_subprocess(cmd_args)
|
|
||||||
except TypeError as error:
|
|
||||||
raise TypeError(
|
|
||||||
"Error creating `{}` due: {}".format(fpath, error))
|
|
||||||
|
|
||||||
def _make_single_clip_media_info(self, fpath):
|
|
||||||
with open(fpath) as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
_added_root = itertools.chain(
|
|
||||||
"<root>", deepcopy(lines)[1:], "</root>")
|
|
||||||
new_root = ET.fromstringlist(_added_root)
|
|
||||||
|
|
||||||
# find the clip which is matching to my input name
|
|
||||||
xml_clips = new_root.findall("clip")
|
|
||||||
matching_clip = None
|
|
||||||
for xml_clip in xml_clips:
|
|
||||||
if xml_clip.find("name").text in self.feed_basename:
|
|
||||||
matching_clip = xml_clip
|
|
||||||
|
|
||||||
if matching_clip is None:
|
|
||||||
# return warning there is missing clip
|
|
||||||
raise ET.ParseError(
|
|
||||||
"Missing clip in `{}`. Available clips {}".format(
|
|
||||||
self.feed_basename, [
|
|
||||||
xml_clip.find("name").text
|
|
||||||
for xml_clip in xml_clips
|
|
||||||
]
|
|
||||||
))
|
|
||||||
|
|
||||||
return matching_clip
|
|
||||||
|
|
||||||
def _get_time_info_from_origin(self, xml_data):
|
|
||||||
try:
|
|
||||||
for out_track in xml_data.iter('track'):
|
|
||||||
for out_feed in out_track.iter('feed'):
|
|
||||||
# start frame
|
|
||||||
out_feed_nb_ticks_obj = out_feed.find(
|
|
||||||
'startTimecode/nbTicks')
|
|
||||||
self.start_frame = out_feed_nb_ticks_obj.text
|
|
||||||
|
|
||||||
# fps
|
|
||||||
out_feed_fps_obj = out_feed.find(
|
|
||||||
'startTimecode/rate')
|
|
||||||
self.fps = out_feed_fps_obj.text
|
|
||||||
|
|
||||||
# drop frame mode
|
|
||||||
out_feed_drop_mode_obj = out_feed.find(
|
|
||||||
'startTimecode/dropMode')
|
|
||||||
self.drop_mode = out_feed_drop_mode_obj.text
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
except Exception as msg:
|
|
||||||
self.log.warning(msg)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def write_clip_data_to_file(fpath, xml_data):
|
|
||||||
log.info(">>> type of xml_data: {}".format(type(xml_data)))
|
|
||||||
if isinstance(xml_data, ET.ElementTree):
|
|
||||||
xml_data = xml_data.getroot()
|
|
||||||
try:
|
|
||||||
# save it as new file
|
|
||||||
tree = cET.ElementTree(xml_data)
|
|
||||||
tree.write(
|
|
||||||
fpath, xml_declaration=True,
|
|
||||||
method='xml', encoding='UTF-8'
|
|
||||||
)
|
|
||||||
except IOError as error:
|
|
||||||
raise IOError(
|
|
||||||
"Not able to write data to file: {}".format(error))
|
|
||||||
|
|
||||||
|
|
||||||
class OpenClipSolver(MediaInfoFile):
|
|
||||||
create_new_clip = False
|
|
||||||
|
|
||||||
log = log
|
|
||||||
|
|
||||||
def __init__(self, openclip_file_path, feed_data):
|
|
||||||
self.out_file = openclip_file_path
|
|
||||||
|
|
||||||
# new feed variables:
|
|
||||||
feed_path = feed_data.pop("path")
|
|
||||||
|
|
||||||
# initialize parent class
|
|
||||||
super(OpenClipSolver, self).__init__(
|
|
||||||
feed_path,
|
|
||||||
**feed_data
|
|
||||||
)
|
|
||||||
|
|
||||||
# get other metadata
|
|
||||||
self.feed_version_name = feed_data["version"]
|
|
||||||
self.feed_colorspace = feed_data.get("colorspace")
|
|
||||||
self.log.info("feed_version_name: {}".format(self.feed_version_name))
|
|
||||||
|
|
||||||
# derivate other feed variables
|
|
||||||
self.feed_basename = os.path.basename(feed_path)
|
|
||||||
self.feed_dir = os.path.dirname(feed_path)
|
|
||||||
self.feed_ext = os.path.splitext(self.feed_basename)[1][1:].lower()
|
|
||||||
self.log.info("feed_ext: {}".format(self.feed_ext))
|
|
||||||
self.log.info("out_file: {}".format(self.out_file))
|
|
||||||
if not self._is_valid_tmp_file(self.out_file):
|
|
||||||
self.create_new_clip = True
|
|
||||||
|
|
||||||
def _is_valid_tmp_file(self, file):
|
|
||||||
# check if file exists
|
|
||||||
if os.path.isfile(file):
|
|
||||||
# test also if file is not empty
|
|
||||||
with open(file) as f:
|
|
||||||
lines = f.readlines()
|
|
||||||
if len(lines) > 2:
|
|
||||||
return True
|
|
||||||
|
|
||||||
# file is probably corrupted
|
|
||||||
os.remove(file)
|
|
||||||
return False
|
|
||||||
|
|
||||||
def make(self):
|
|
||||||
|
|
||||||
if self.create_new_clip:
|
|
||||||
# New openClip
|
|
||||||
self._create_new_open_clip()
|
|
||||||
else:
|
|
||||||
self._update_open_clip()
|
|
||||||
|
|
||||||
def _clear_handler(self, xml_object):
|
|
||||||
for handler in xml_object.findall("./handler"):
|
|
||||||
self.log.info("Handler found")
|
|
||||||
xml_object.remove(handler)
|
|
||||||
|
|
||||||
def _create_new_open_clip(self):
|
|
||||||
self.log.info("Building new openClip")
|
|
||||||
self.log.info(">> self.clip_data: {}".format(self.clip_data))
|
|
||||||
|
|
||||||
# clip data comming from MediaInfoFile
|
|
||||||
tmp_xml_feeds = self.clip_data.find('tracks/track/feeds')
|
|
||||||
tmp_xml_feeds.set('currentVersion', self.feed_version_name)
|
|
||||||
for tmp_feed in tmp_xml_feeds:
|
|
||||||
tmp_feed.set('vuid', self.feed_version_name)
|
|
||||||
|
|
||||||
# add colorspace if any is set
|
|
||||||
if self.feed_colorspace:
|
|
||||||
self._add_colorspace(tmp_feed, self.feed_colorspace)
|
|
||||||
|
|
||||||
self._clear_handler(tmp_feed)
|
|
||||||
|
|
||||||
tmp_xml_versions_obj = self.clip_data.find('versions')
|
|
||||||
tmp_xml_versions_obj.set('currentVersion', self.feed_version_name)
|
|
||||||
for xml_new_version in tmp_xml_versions_obj:
|
|
||||||
xml_new_version.set('uid', self.feed_version_name)
|
|
||||||
xml_new_version.set('type', 'version')
|
|
||||||
|
|
||||||
self._clear_handler(self.clip_data)
|
|
||||||
self.log.info("Adding feed version: {}".format(self.feed_basename))
|
|
||||||
|
|
||||||
self.write_clip_data_to_file(self.out_file, self.clip_data)
|
|
||||||
|
|
||||||
def _update_open_clip(self):
|
|
||||||
self.log.info("Updating openClip ..")
|
|
||||||
|
|
||||||
out_xml = ET.parse(self.out_file)
|
|
||||||
|
|
||||||
self.log.info(">> out_xml: {}".format(out_xml))
|
|
||||||
self.log.info(">> self.clip_data: {}".format(self.clip_data))
|
|
||||||
|
|
||||||
# Get new feed from tmp file
|
|
||||||
tmp_xml_feed = self.clip_data.find('tracks/track/feeds/feed')
|
|
||||||
|
|
||||||
self._clear_handler(tmp_xml_feed)
|
|
||||||
|
|
||||||
# update fps from MediaInfoFile class
|
|
||||||
if self.fps:
|
|
||||||
tmp_feed_fps_obj = tmp_xml_feed.find(
|
|
||||||
"startTimecode/rate")
|
|
||||||
tmp_feed_fps_obj.text = str(self.fps)
|
|
||||||
|
|
||||||
# update start_frame from MediaInfoFile class
|
|
||||||
if self.start_frame:
|
|
||||||
tmp_feed_nb_ticks_obj = tmp_xml_feed.find(
|
|
||||||
"startTimecode/nbTicks")
|
|
||||||
tmp_feed_nb_ticks_obj.text = str(self.start_frame)
|
|
||||||
|
|
||||||
# update drop_mode from MediaInfoFile class
|
|
||||||
if self.drop_mode:
|
|
||||||
tmp_feed_drop_mode_obj = tmp_xml_feed.find(
|
|
||||||
"startTimecode/dropMode")
|
|
||||||
tmp_feed_drop_mode_obj.text = str(self.drop_mode)
|
|
||||||
|
|
||||||
new_path_obj = tmp_xml_feed.find(
|
|
||||||
"spans/span/path")
|
|
||||||
new_path = new_path_obj.text
|
|
||||||
|
|
||||||
feed_added = False
|
|
||||||
if not self._feed_exists(out_xml, new_path):
|
|
||||||
tmp_xml_feed.set('vuid', self.feed_version_name)
|
|
||||||
# Append new temp file feed to .clip source out xml
|
|
||||||
out_track = out_xml.find("tracks/track")
|
|
||||||
# add colorspace if any is set
|
|
||||||
if self.feed_colorspace:
|
|
||||||
self._add_colorspace(tmp_xml_feed, self.feed_colorspace)
|
|
||||||
|
|
||||||
out_feeds = out_track.find('feeds')
|
|
||||||
out_feeds.set('currentVersion', self.feed_version_name)
|
|
||||||
out_feeds.append(tmp_xml_feed)
|
|
||||||
|
|
||||||
self.log.info(
|
|
||||||
"Appending new feed: {}".format(
|
|
||||||
self.feed_version_name))
|
|
||||||
feed_added = True
|
|
||||||
|
|
||||||
if feed_added:
|
|
||||||
# Append vUID to versions
|
|
||||||
out_xml_versions_obj = out_xml.find('versions')
|
|
||||||
out_xml_versions_obj.set(
|
|
||||||
'currentVersion', self.feed_version_name)
|
|
||||||
new_version_obj = ET.Element(
|
|
||||||
"version", {"type": "version", "uid": self.feed_version_name})
|
|
||||||
out_xml_versions_obj.insert(0, new_version_obj)
|
|
||||||
|
|
||||||
self._clear_handler(out_xml)
|
|
||||||
|
|
||||||
# fist create backup
|
|
||||||
self._create_openclip_backup_file(self.out_file)
|
|
||||||
|
|
||||||
self.log.info("Adding feed version: {}".format(
|
|
||||||
self.feed_version_name))
|
|
||||||
|
|
||||||
self.write_clip_data_to_file(self.out_file, out_xml)
|
|
||||||
|
|
||||||
self.log.info("openClip Updated: {}".format(self.out_file))
|
|
||||||
|
|
||||||
def _feed_exists(self, xml_data, path):
|
|
||||||
# loop all available feed paths and check if
|
|
||||||
# the path is not already in file
|
|
||||||
for src_path in xml_data.iter('path'):
|
|
||||||
if path == src_path.text:
|
|
||||||
self.log.warning(
|
|
||||||
"Not appending file as it already is in .clip file")
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _create_openclip_backup_file(self, file):
|
|
||||||
bck_file = "{}.bak".format(file)
|
|
||||||
# if backup does not exist
|
|
||||||
if not os.path.isfile(bck_file):
|
|
||||||
shutil.copy2(file, bck_file)
|
|
||||||
else:
|
|
||||||
# in case it exists and is already multiplied
|
|
||||||
created = False
|
|
||||||
for _i in range(1, 99):
|
|
||||||
bck_file = "{name}.bak.{idx:0>2}".format(
|
|
||||||
name=file,
|
|
||||||
idx=_i)
|
|
||||||
# create numbered backup file
|
|
||||||
if not os.path.isfile(bck_file):
|
|
||||||
shutil.copy2(file, bck_file)
|
|
||||||
created = True
|
|
||||||
break
|
|
||||||
# in case numbered does not exists
|
|
||||||
if not created:
|
|
||||||
bck_file = "{}.bak.last".format(file)
|
|
||||||
shutil.copy2(file, bck_file)
|
|
||||||
|
|
||||||
def _add_colorspace(self, feed_obj, profile_name):
|
|
||||||
feed_storage_obj = feed_obj.find("storageFormat")
|
|
||||||
feed_clr_obj = feed_storage_obj.find("colourSpace")
|
|
||||||
if feed_clr_obj is not None:
|
|
||||||
feed_clr_obj = ET.Element(
|
|
||||||
"colourSpace", {"type": "string"})
|
|
||||||
feed_storage_obj.append(feed_clr_obj)
|
|
||||||
|
|
||||||
feed_clr_obj.text = profile_name
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
from openpype.lib import import_filepath
|
|
||||||
|
|
||||||
plugin = import_filepath(
|
|
||||||
"/Users/pype.club/code/openpype/openpype/hosts/flame/api/test_plugin.py")
|
|
||||||
|
|
||||||
openclip_file_path = "/Users/pype.club/FLAME_STORAGE/test_shot_fps_float/test.clip"
|
|
||||||
# feed_datas = [
|
|
||||||
# {
|
|
||||||
# "path": "/Users/pype.club/pype_club_root/OP02_VFX_demo/shots/a/a0000001/publish/plate/plateMain/v007/op02vfx_a0000001_plateMain_v007_exr16fpdwaaCl.0997.exr",
|
|
||||||
# "version": "v007"
|
|
||||||
# },
|
|
||||||
# {
|
|
||||||
# "path": "/Users/pype.club/pype_club_root/OP02_VFX_demo/shots/a/a0000001/publish/plate/plateMain/v008/op02vfx_a0000001_plateMain_v008_exr16fpdwaaCl.0997.exr",
|
|
||||||
# "version": "v008"
|
|
||||||
# }
|
|
||||||
# ]
|
|
||||||
|
|
||||||
feed_datas = [
|
|
||||||
{
|
|
||||||
"path": "/Users/pype.club/FLAME_STORAGE/test_shot_fps_float/v001/file_name_v001.1001.exr",
|
|
||||||
"version": "v001"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "/Users/pype.club/FLAME_STORAGE/test_shot_fps_float/v002/file_name_v002.1001.exr",
|
|
||||||
"version": "v002"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
for feed_data in feed_datas:
|
|
||||||
oclip = plugin.OpenClipSolver(openclip_file_path, feed_data)
|
|
||||||
oclip.make()
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue