mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 12:54:40 +01:00
Merge branch 'release/2.13.4' into 2.x/develop
This commit is contained in:
commit
bcd57e5177
25 changed files with 238 additions and 76 deletions
|
|
@ -978,24 +978,30 @@ class WorkfileSettings(object):
|
|||
self.set_colorspace()
|
||||
|
||||
def set_favorites(self):
|
||||
anatomy = get_anatomy()
|
||||
work_template = anatomy.templates["work"]["path"]
|
||||
projects_root = anatomy.root_value_for_template(work_template)
|
||||
work_dir = os.getenv("AVALON_WORKDIR")
|
||||
asset = os.getenv("AVALON_ASSET")
|
||||
project = os.getenv("AVALON_PROJECT")
|
||||
hierarchy = os.getenv("AVALON_HIERARCHY")
|
||||
favorite_items = OrderedDict()
|
||||
|
||||
# project
|
||||
favorite_items.update({"Project dir": os.path.join(
|
||||
projects_root, project).replace("\\", "/")})
|
||||
# shot
|
||||
favorite_items.update({"Shot dir": os.path.join(
|
||||
projects_root, project,
|
||||
hierarchy, asset).replace("\\", "/")})
|
||||
# get project's root and split to parts
|
||||
projects_root = os.path.normpath(work_dir.split(
|
||||
project)[0])
|
||||
# add project name
|
||||
project_dir = os.path.join(projects_root, project) + "/"
|
||||
# add to favorites
|
||||
favorite_items.update({"Project dir": project_dir.replace("\\", "/")})
|
||||
|
||||
# asset
|
||||
asset_root = os.path.normpath(work_dir.split(
|
||||
asset)[0])
|
||||
# add asset name
|
||||
asset_dir = os.path.join(asset_root, asset) + "/"
|
||||
# add to favorites
|
||||
favorite_items.update({"Shot dir": asset_dir.replace("\\", "/")})
|
||||
|
||||
# workdir
|
||||
favorite_items.update({"Work dir": work_dir})
|
||||
favorite_items.update({"Work dir": work_dir.replace("\\", "/")})
|
||||
|
||||
set_context_favorites(favorite_items)
|
||||
|
||||
|
|
@ -1388,8 +1394,18 @@ class ExporterReviewMov(ExporterReview):
|
|||
self.log.debug("Path: {}".format(self.path))
|
||||
write_node["file"].setValue(self.path)
|
||||
write_node["file_type"].setValue(self.ext)
|
||||
write_node["meta_codec"].setValue("ap4h")
|
||||
write_node["mov64_codec"].setValue("ap4h")
|
||||
|
||||
# Knobs `meta_codec` and `mov64_codec` are not available on centos.
|
||||
# TODO change this to use conditions, if possible.
|
||||
try:
|
||||
write_node["meta_codec"].setValue("ap4h")
|
||||
except Exception:
|
||||
self.log.info("`meta_codec` knob was not found")
|
||||
|
||||
try:
|
||||
write_node["mov64_codec"].setValue("ap4h")
|
||||
except Exception:
|
||||
self.log.info("`mov64_codec` knob was not found")
|
||||
write_node["mov64_write_timecode"].setValue(1)
|
||||
write_node["raw"].setValue(1)
|
||||
# connect
|
||||
|
|
|
|||
27
pype/lib.py
27
pype/lib.py
|
|
@ -1420,13 +1420,15 @@ class BuildWorkfile:
|
|||
return output
|
||||
|
||||
|
||||
def ffprobe_streams(path_to_file):
|
||||
def ffprobe_streams(path_to_file, logger=None):
|
||||
"""Load streams from entered filepath via ffprobe."""
|
||||
log.info(
|
||||
if not logger:
|
||||
logger = log
|
||||
logger.info(
|
||||
"Getting information about input \"{}\".".format(path_to_file)
|
||||
)
|
||||
args = [
|
||||
get_ffmpeg_tool_path("ffprobe"),
|
||||
"\"{}\"".format(get_ffmpeg_tool_path("ffprobe")),
|
||||
"-v quiet",
|
||||
"-print_format json",
|
||||
"-show_format",
|
||||
|
|
@ -1434,12 +1436,21 @@ def ffprobe_streams(path_to_file):
|
|||
"\"{}\"".format(path_to_file)
|
||||
]
|
||||
command = " ".join(args)
|
||||
log.debug("FFprobe command: \"{}\"".format(command))
|
||||
popen = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)
|
||||
logger.debug("FFprobe command: \"{}\"".format(command))
|
||||
popen = subprocess.Popen(
|
||||
command,
|
||||
shell=True,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE
|
||||
)
|
||||
|
||||
popen_output = popen.communicate()[0]
|
||||
log.debug("FFprobe output: {}".format(popen_output))
|
||||
return json.loads(popen_output)["streams"]
|
||||
popen_stdout, popen_stderr = popen.communicate()
|
||||
if popen_stdout:
|
||||
logger.debug("ffprobe stdout: {}".format(popen_stdout))
|
||||
|
||||
if popen_stderr:
|
||||
logger.debug("ffprobe stderr: {}".format(popen_stderr))
|
||||
return json.loads(popen_stdout)["streams"]
|
||||
|
||||
|
||||
def source_hash(filepath, *args):
|
||||
|
|
|
|||
|
|
@ -974,7 +974,7 @@ class ExtractBurnin(pype.api.Extractor):
|
|||
|
||||
args = [executable, scriptpath, json_data]
|
||||
self.log.debug("Executing: {}".format(args))
|
||||
output = pype.api.subprocess(args, shell=True)
|
||||
output = pype.api.subprocess(args, shell=True, logger=self.log)
|
||||
self.log.debug("Output: {}".format(output))
|
||||
|
||||
repre_update = {
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class ExtractJpegEXR(pyblish.api.InstancePlugin):
|
|||
ffmpeg_args = self.ffmpeg_args or {}
|
||||
|
||||
jpeg_items = []
|
||||
jpeg_items.append(ffmpeg_path)
|
||||
jpeg_items.append("\"{}\"".format(ffmpeg_path))
|
||||
# override file if already exists
|
||||
jpeg_items.append("-y")
|
||||
# use same input args like with mov
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
audio_filters.append(arg)
|
||||
|
||||
all_args = []
|
||||
all_args.append(self.ffmpeg_path)
|
||||
all_args.append("\"{}\"".format(self.ffmpeg_path))
|
||||
all_args.extend(input_args)
|
||||
if video_filters:
|
||||
all_args.append("-filter:v {}".format(",".join(video_filters)))
|
||||
|
|
@ -649,7 +649,9 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
|
||||
# NOTE Skipped using instance's resolution
|
||||
full_input_path_single_file = temp_data["full_input_path_single_file"]
|
||||
input_data = pype.lib.ffprobe_streams(full_input_path_single_file)[0]
|
||||
input_data = pype.lib.ffprobe_streams(
|
||||
full_input_path_single_file, self.log
|
||||
)[0]
|
||||
input_width = int(input_data["width"])
|
||||
input_height = int(input_data["height"])
|
||||
|
||||
|
|
@ -1542,7 +1544,7 @@ class ExtractReview(pyblish.api.InstancePlugin):
|
|||
os.mkdir(stg_dir)
|
||||
|
||||
mov_args = [
|
||||
ffmpeg_path,
|
||||
"\"{}\"".format(ffmpeg_path),
|
||||
" ".join(input_args),
|
||||
" ".join(output_args)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class ExtractReviewSlate(pype.api.Extractor):
|
|||
slate_path = inst_data.get("slateFrame")
|
||||
ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg")
|
||||
|
||||
slate_stream = pype.lib.ffprobe_streams(slate_path)[0]
|
||||
slate_stream = pype.lib.ffprobe_streams(slate_path, self.log)[0]
|
||||
slate_width = slate_stream["width"]
|
||||
slate_height = slate_stream["height"]
|
||||
|
||||
|
|
@ -178,7 +178,7 @@ class ExtractReviewSlate(pype.api.Extractor):
|
|||
_remove_at_end.append(slate_v_path)
|
||||
|
||||
slate_args = [
|
||||
ffmpeg_path,
|
||||
"\"{}\"".format(ffmpeg_path),
|
||||
" ".join(input_args),
|
||||
" ".join(output_args)
|
||||
]
|
||||
|
|
@ -299,7 +299,7 @@ class ExtractReviewSlate(pype.api.Extractor):
|
|||
|
||||
try:
|
||||
# Get information about input file via ffprobe tool
|
||||
streams = pype.lib.ffprobe_streams(full_input_path)
|
||||
streams = pype.lib.ffprobe_streams(full_input_path, self.log)
|
||||
except Exception:
|
||||
self.log.warning(
|
||||
"Could not get codec data from input.",
|
||||
|
|
|
|||
|
|
@ -615,12 +615,12 @@ class IntegrateAssetNew(pyblish.api.InstancePlugin):
|
|||
|
||||
# copy file with speedcopy and check if size of files are simetrical
|
||||
while True:
|
||||
import shutil
|
||||
try:
|
||||
if not shutil._samefile(src, dst):
|
||||
copyfile(src, dst)
|
||||
except shutil.SameFileError:
|
||||
self.log.critical("files are the same {} to {}".format(src,
|
||||
dst))
|
||||
else:
|
||||
self.log.critical(
|
||||
"files are the same {} to {}".format(src, dst)
|
||||
)
|
||||
os.remove(dst)
|
||||
try:
|
||||
shutil.copyfile(src, dst)
|
||||
|
|
|
|||
|
|
@ -1024,6 +1024,8 @@ class ProcessSubmittedJobOnFarm(pyblish.api.InstancePlugin):
|
|||
version = pype.api.get_latest_version(asset, subset)
|
||||
if version:
|
||||
version = int(version["name"]) + 1
|
||||
else:
|
||||
version = 1
|
||||
|
||||
template_data["subset"] = subset
|
||||
template_data["family"] = "render"
|
||||
|
|
|
|||
|
|
@ -29,6 +29,6 @@ class ValidateFFmpegInstalled(pyblish.api.ContextPlugin):
|
|||
def process(self, context):
|
||||
ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg")
|
||||
self.log.info("ffmpeg path: `{}`".format(ffmpeg_path))
|
||||
if self.is_tool(ffmpeg_path) is False:
|
||||
if self.is_tool("\"{}\"".format(ffmpeg_path)) is False:
|
||||
self.log.error("ffmpeg not found in PATH")
|
||||
raise RuntimeError('ffmpeg not installed.')
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ class ExtractRender(pyblish.api.InstancePlugin):
|
|||
thumbnail_path = os.path.join(path, "thumbnail.png")
|
||||
ffmpeg_path = pype.lib.get_ffmpeg_tool_path("ffmpeg")
|
||||
args = [
|
||||
ffmpeg_path, "-y",
|
||||
"\"{}\"".format(ffmpeg_path), "-y",
|
||||
"-i", os.path.join(path, list(collections[0])[0]),
|
||||
"-vf", "scale=300:-1",
|
||||
"-vframes", "1",
|
||||
|
|
|
|||
|
|
@ -130,8 +130,8 @@ class ExtractReviewCutUp(pype.api.Extractor):
|
|||
|
||||
# check if audio stream is in input video file
|
||||
ffprob_cmd = (
|
||||
"{ffprobe_path} -i \"{full_input_path}\" -show_streams "
|
||||
"-select_streams a -loglevel error"
|
||||
"\"{ffprobe_path}\" -i \"{full_input_path}\" -show_streams"
|
||||
" -select_streams a -loglevel error"
|
||||
).format(**locals())
|
||||
|
||||
self.log.debug("ffprob_cmd: {}".format(ffprob_cmd))
|
||||
|
|
@ -171,7 +171,8 @@ class ExtractReviewCutUp(pype.api.Extractor):
|
|||
# try to get video native resolution data
|
||||
try:
|
||||
resolution_output = pype.api.subprocess((
|
||||
"{ffprobe_path} -i \"{full_input_path}\" -v error "
|
||||
"\"{ffprobe_path}\" -i \"{full_input_path}\""
|
||||
" -v error "
|
||||
"-select_streams v:0 -show_entries "
|
||||
"stream=width,height -of csv=s=x:p=0"
|
||||
).format(**locals()))
|
||||
|
|
@ -274,7 +275,7 @@ class ExtractReviewCutUp(pype.api.Extractor):
|
|||
output_args.append("-y \"{}\"".format(full_output_path))
|
||||
|
||||
mov_args = [
|
||||
ffmpeg_path,
|
||||
"\"{}\"".format(ffmpeg_path),
|
||||
" ".join(input_args),
|
||||
" ".join(output_args)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -34,8 +34,6 @@ class ExtractImage(pype.api.Extractor):
|
|||
# limit unnecessary calls to client
|
||||
if layer.visible and layer.id not in extract_ids:
|
||||
stub.set_visible(layer.id, False)
|
||||
if not layer.visible and layer.id in extract_ids:
|
||||
stub.set_visible(layer.id, True)
|
||||
|
||||
save_options = []
|
||||
if "png" in self.formats:
|
||||
|
|
|
|||
|
|
@ -38,8 +38,6 @@ class ExtractReview(pype.api.Extractor):
|
|||
# limit unnecessary calls to client
|
||||
if layer.visible and layer.id not in extract_ids:
|
||||
stub.set_visible(layer.id, False)
|
||||
if not layer.visible and layer.id in extract_ids:
|
||||
stub.set_visible(layer.id, True)
|
||||
|
||||
stub.saveAs(output_image_path, 'jpg', True)
|
||||
|
||||
|
|
@ -56,7 +54,7 @@ class ExtractReview(pype.api.Extractor):
|
|||
# Generate thumbnail.
|
||||
thumbnail_path = os.path.join(staging_dir, "thumbnail.jpg")
|
||||
args = [
|
||||
ffmpeg_path, "-y",
|
||||
"\"{}\"".format(ffmpeg_path), "-y",
|
||||
"-i", output_image_path,
|
||||
"-vf", "scale=300:-1",
|
||||
"-vframes", "1",
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ class ExtractShotData(pype.api.Extractor):
|
|||
start += 0.5
|
||||
|
||||
args = [
|
||||
ffmpeg_path,
|
||||
"\"{}\"".format(ffmpeg_path),
|
||||
"-ss", str(start / fps),
|
||||
"-i", f"\"{video_file_path}\"",
|
||||
"-t", str(dur / fps)
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ class ExtractThumbnailSP(pyblish.api.InstancePlugin):
|
|||
ffmpeg_args = self.ffmpeg_args or {}
|
||||
|
||||
jpeg_items = []
|
||||
jpeg_items.append(ffmpeg_path)
|
||||
jpeg_items.append("\"{}\"".format(ffmpeg_path))
|
||||
# override file if already exists
|
||||
jpeg_items.append("-y")
|
||||
# add input filters from peresets
|
||||
|
|
|
|||
|
|
@ -10,12 +10,28 @@ def get_resource(*args):
|
|||
"""
|
||||
return os.path.normpath(
|
||||
os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
os.path.dirname(os.path.abspath(__file__)),
|
||||
*args
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def get_liberation_font_path(bold=False, italic=False):
|
||||
font_name = "LiberationSans"
|
||||
suffix = ""
|
||||
if bold:
|
||||
suffix += "Bold"
|
||||
if italic:
|
||||
suffix += "Italic"
|
||||
|
||||
if not suffix:
|
||||
suffix = "Regular"
|
||||
|
||||
filename = "{}-{}.ttf".format(font_name, suffix)
|
||||
font_path = get_resource("fonts", font_name, filename)
|
||||
return font_path
|
||||
|
||||
|
||||
def pype_icon_filepath(debug=None):
|
||||
if debug is None:
|
||||
debug = bool(os.getenv("PYPE_DEV"))
|
||||
|
|
|
|||
BIN
pype/resources/fonts/LiberationSans/LiberationSans-Bold.ttf
Normal file
BIN
pype/resources/fonts/LiberationSans/LiberationSans-Bold.ttf
Normal file
Binary file not shown.
Binary file not shown.
BIN
pype/resources/fonts/LiberationSans/LiberationSans-Italic.ttf
Normal file
BIN
pype/resources/fonts/LiberationSans/LiberationSans-Italic.ttf
Normal file
Binary file not shown.
BIN
pype/resources/fonts/LiberationSans/LiberationSans-Regular.ttf
Normal file
BIN
pype/resources/fonts/LiberationSans/LiberationSans-Regular.ttf
Normal file
Binary file not shown.
77
pype/resources/fonts/LiberationSans/License.txt
Normal file
77
pype/resources/fonts/LiberationSans/License.txt
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
LICENSE AGREEMENT AND LIMITED PRODUCT WARRANTY LIBERATION FONT SOFTWARE
|
||||
This agreement governs the use of the Software and any updates to the
|
||||
Software, regardless of the delivery mechanism. Subject to the following
|
||||
terms, Red Hat, Inc. ("Red Hat") grants to the user ("Client") a license to
|
||||
this collective work pursuant to the GNU General Public License v.2 with the
|
||||
exceptions set forth below and such other terms as our set forth in this End
|
||||
User License Agreement.
|
||||
1. The Software and License Exception. LIBERATION font software (the
|
||||
"Software") consists of TrueType-OpenType formatted font software for
|
||||
rendering LIBERATION typefaces in sans serif, serif, and monospaced character
|
||||
styles. You are licensed to use, modify, copy, and distribute the Software
|
||||
pursuant to the GNU General Public License v.2 with the following exceptions:
|
||||
1) As a special exception, if you create a document which uses this font, and
|
||||
embed this font or unaltered portions of this font into the document, this
|
||||
font does not by itself cause the resulting document to be covered by the GNU
|
||||
General Public License. This exception does not however invalidate any other
|
||||
reasons why the document might be covered by the GNU General Public License.
|
||||
If you modify this font, you may extend this exception to your version of the
|
||||
font, but you are not obligated to do so. If you do not wish to do so, delete
|
||||
this exception statement from your version.
|
||||
|
||||
2) As a further exception, any distribution of the object code of the Software
|
||||
in a physical product must provide you the right to access and modify the
|
||||
source code for the Software and to reinstall that modified version of the
|
||||
Software in object code form on the same physical product on which you
|
||||
received it.
|
||||
2. Intellectual Property Rights. The Software and each of its components,
|
||||
including the source code, documentation, appearance, structure and
|
||||
organization are owned by Red Hat and others and are protected under copyright
|
||||
and other laws. Title to the Software and any component, or to any copy,
|
||||
modification, or merged portion shall remain with the aforementioned, subject
|
||||
to the applicable license. The "LIBERATION" trademark is a trademark of Red
|
||||
Hat, Inc. in the U.S. and other countries. This agreement does not permit
|
||||
Client to distribute modified versions of the Software using Red Hat's
|
||||
trademarks. If Client makes a redistribution of a modified version of the
|
||||
Software, then Client must modify the files names to remove any reference to
|
||||
the Red Hat trademarks and must not use the Red Hat trademarks in any way to
|
||||
reference or promote the modified Software.
|
||||
3. Limited Warranty. To the maximum extent permitted under applicable law, the
|
||||
Software is provided and licensed "as is" without warranty of any kind,
|
||||
expressed or implied, including the implied warranties of merchantability,
|
||||
non-infringement or fitness for a particular purpose. Red Hat does not warrant
|
||||
that the functions contained in the Software will meet Client's requirements
|
||||
or that the operation of the Software will be entirely error free or appear
|
||||
precisely as described in the accompanying documentation.
|
||||
4. Limitation of Remedies and Liability. To the maximum extent permitted by
|
||||
applicable law, Red Hat or any Red Hat authorized dealer will not be liable to
|
||||
Client for any incidental or consequential damages, including lost profits or
|
||||
lost savings arising out of the use or inability to use the Software, even if
|
||||
Red Hat or such dealer has been advised of the possibility of such damages.
|
||||
5. Export Control. As required by U.S. law, Client represents and warrants
|
||||
that it: (a) understands that the Software is subject to export controls under
|
||||
the U.S. Commerce Department's Export Administration Regulations ("EAR"); (b)
|
||||
is not located in a prohibited destination country under the EAR or U.S.
|
||||
sanctions regulations (currently Cuba, Iran, Iraq, Libya, North Korea, Sudan
|
||||
and Syria); (c) will not export, re-export, or transfer the Software to any
|
||||
prohibited destination, entity, or individual without the necessary export
|
||||
license(s) or authorizations(s) from the U.S. Government; (d) will not use or
|
||||
transfer the Software for use in any sensitive nuclear, chemical or biological
|
||||
weapons, or missile technology end-uses unless authorized by the U.S.
|
||||
Government by regulation or specific license; (e) understands and agrees that
|
||||
if it is in the United States and exports or transfers the Software to
|
||||
eligible end users, it will, as required by EAR Section 740.17(e), submit
|
||||
semi-annual reports to the Commerce Department's Bureau of Industry & Security
|
||||
(BIS), which include the name and address (including country) of each
|
||||
transferee; and (f) understands that countries other than the United States
|
||||
may restrict the import, use, or export of encryption products and that it
|
||||
shall be solely responsible for compliance with any such import, use, or
|
||||
export restrictions.
|
||||
6. General. If any provision of this agreement is held to be unenforceable,
|
||||
that shall not affect the enforceability of the remaining provisions. This
|
||||
agreement shall be governed by the laws of the State of North Carolina and of
|
||||
the United States, without regard to any conflict of laws provisions, except
|
||||
that the United Nations Convention on the International Sale of Goods shall
|
||||
not apply.
|
||||
Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark
|
||||
of Red Hat, Inc.
|
||||
|
|
@ -2,9 +2,10 @@ import os
|
|||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
import platform
|
||||
import json
|
||||
import opentimelineio_contrib.adapters.ffmpeg_burnins as ffmpeg_burnins
|
||||
from pype.api import config
|
||||
from pype.api import config, resources
|
||||
import pype.lib
|
||||
|
||||
|
||||
|
|
@ -13,16 +14,16 @@ ffprobe_path = pype.lib.get_ffmpeg_tool_path("ffprobe")
|
|||
|
||||
|
||||
FFMPEG = (
|
||||
'{} -i "%(input)s" %(filters)s %(args)s%(output)s'
|
||||
'"{}" -i "%(input)s" %(filters)s %(args)s%(output)s'
|
||||
).format(ffmpeg_path)
|
||||
|
||||
FFPROBE = (
|
||||
'{} -v quiet -print_format json -show_format -show_streams "%(source)s"'
|
||||
'"{}" -v quiet -print_format json -show_format -show_streams "%(source)s"'
|
||||
).format(ffprobe_path)
|
||||
|
||||
DRAWTEXT = (
|
||||
"drawtext=text=\\'%(text)s\\':x=%(x)s:y=%(y)s:fontcolor="
|
||||
"%(color)s@%(opacity).1f:fontsize=%(size)d:fontfile='%(font)s'"
|
||||
"drawtext=fontfile='%(font)s':text=\\'%(text)s\\':"
|
||||
"x=%(x)s:y=%(y)s:fontcolor=%(color)s@%(opacity).1f:fontsize=%(size)d"
|
||||
)
|
||||
TIMECODE = (
|
||||
"drawtext=timecode=\\'%(timecode)s\\':text=\\'%(text)s\\'"
|
||||
|
|
@ -236,13 +237,32 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins):
|
|||
}
|
||||
timecode_text = options.get("timecode") or ""
|
||||
text_for_size += timecode_text
|
||||
|
||||
data.update(options)
|
||||
|
||||
os_system = platform.system().lower()
|
||||
data_font = data.get("font")
|
||||
if not data_font:
|
||||
data_font = (
|
||||
resources.get_liberation_font_path().replace("\\", "/")
|
||||
)
|
||||
elif isinstance(data_font, dict):
|
||||
data_font = data_font[os_system]
|
||||
|
||||
if data_font:
|
||||
data["font"] = data_font
|
||||
options["font"] = data_font
|
||||
if ffmpeg_burnins._is_windows():
|
||||
data["font"] = (
|
||||
data_font
|
||||
.replace(os.sep, r'\\' + os.sep)
|
||||
.replace(':', r'\:')
|
||||
)
|
||||
|
||||
data.update(
|
||||
ffmpeg_burnins._drawtext(align, resolution, text_for_size, options)
|
||||
)
|
||||
if 'font' in data and ffmpeg_burnins._is_windows():
|
||||
data['font'] = data['font'].replace(os.sep, r'\\' + os.sep)
|
||||
data['font'] = data['font'].replace(':', r'\:')
|
||||
|
||||
self.filters['drawtext'].append(draw % data)
|
||||
|
||||
if options.get('bg_color') is not None:
|
||||
|
|
@ -474,7 +494,7 @@ def burnins_from_data(
|
|||
# Replace with missing key value if frame_start_tc is not set
|
||||
if frame_start_tc is None and has_timecode:
|
||||
has_timecode = False
|
||||
log.warning(
|
||||
print(
|
||||
"`frame_start` and `frame_start_tc`"
|
||||
" are not set in entered data."
|
||||
)
|
||||
|
|
@ -483,7 +503,7 @@ def burnins_from_data(
|
|||
has_source_timecode = SOURCE_TIMECODE_KEY in value
|
||||
if source_timecode is None and has_source_timecode:
|
||||
has_source_timecode = False
|
||||
log.warning("Source does not have set timecode value.")
|
||||
print("Source does not have set timecode value.")
|
||||
value = value.replace(SOURCE_TIMECODE_KEY, MISSING_KEY_VALUE)
|
||||
|
||||
key_pattern = re.compile(r"(\{.*?[^{0]*\})")
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import os
|
|||
import sys
|
||||
import traceback
|
||||
import inspect
|
||||
import logging
|
||||
|
||||
from Qt import QtCore
|
||||
|
||||
|
|
@ -29,6 +30,7 @@ class IterationBreak(Exception):
|
|||
|
||||
|
||||
class Controller(QtCore.QObject):
|
||||
log = logging.getLogger("PyblishController")
|
||||
# Emitted when the GUI is about to start processing;
|
||||
# e.g. resetting, validating or publishing.
|
||||
about_to_process = QtCore.Signal(object, object)
|
||||
|
|
@ -72,6 +74,8 @@ class Controller(QtCore.QObject):
|
|||
self.instance_toggled.connect(self._on_instance_toggled)
|
||||
|
||||
def reset_variables(self):
|
||||
self.log.debug("Resetting pyblish context variables")
|
||||
|
||||
# Data internal to the GUI itself
|
||||
self.is_running = False
|
||||
self.stopped = False
|
||||
|
|
@ -113,6 +117,7 @@ class Controller(QtCore.QObject):
|
|||
"nextOrder": None,
|
||||
"ordersWithError": set()
|
||||
}
|
||||
self.log.debug("Reset of pyblish context variables done")
|
||||
|
||||
def presets_by_hosts(self):
|
||||
# Get global filters as base
|
||||
|
|
@ -138,6 +143,8 @@ class Controller(QtCore.QObject):
|
|||
return result
|
||||
|
||||
def reset_context(self):
|
||||
self.log.debug("Resetting pyblish context object")
|
||||
|
||||
self.context = pyblish.api.Context()
|
||||
|
||||
self.context._publish_states = InstanceStates.ContextType
|
||||
|
|
@ -159,6 +166,8 @@ class Controller(QtCore.QObject):
|
|||
|
||||
self.context.families = ("__context__",)
|
||||
|
||||
self.log.debug("Reset of pyblish context object done")
|
||||
|
||||
def reset(self):
|
||||
"""Discover plug-ins and run collection."""
|
||||
|
||||
|
|
@ -202,6 +211,7 @@ class Controller(QtCore.QObject):
|
|||
self.was_finished.emit()
|
||||
|
||||
def stop(self):
|
||||
self.log.debug("Stopping")
|
||||
self.stopped = True
|
||||
|
||||
def act(self, plugin, action):
|
||||
|
|
@ -346,27 +356,30 @@ class Controller(QtCore.QObject):
|
|||
This process don't stop on one
|
||||
"""
|
||||
def on_next():
|
||||
self.log.debug("Looking for next pair to process")
|
||||
try:
|
||||
self.current_pair = next(self.pair_generator)
|
||||
if isinstance(self.current_pair, IterationBreak):
|
||||
raise self.current_pair
|
||||
|
||||
except IterationBreak:
|
||||
self.log.debug("Iteration break was raised")
|
||||
self.is_running = False
|
||||
self.was_stopped.emit()
|
||||
return
|
||||
|
||||
except StopIteration:
|
||||
self.log.debug("Iteration stop was raised")
|
||||
self.is_running = False
|
||||
# All pairs were processed successfully!
|
||||
return util.defer(500, on_finished)
|
||||
|
||||
except Exception:
|
||||
# This is a bug
|
||||
exc_type, exc_msg, exc_tb = sys.exc_info()
|
||||
traceback.print_exception(exc_type, exc_msg, exc_tb)
|
||||
self.is_running = False
|
||||
self.was_stopped.emit()
|
||||
except Exception as exc:
|
||||
self.log.warning(
|
||||
"Unexpected exception during `on_next` happened",
|
||||
exc_info=True
|
||||
)
|
||||
exc_msg = str(exc)
|
||||
return util.defer(
|
||||
500, lambda: on_unexpected_error(error=exc_msg)
|
||||
)
|
||||
|
|
@ -376,19 +389,23 @@ class Controller(QtCore.QObject):
|
|||
|
||||
def on_process():
|
||||
try:
|
||||
self.log.debug(
|
||||
"Processing pair: {}".format(str(self.current_pair))
|
||||
)
|
||||
result = self._process(*self.current_pair)
|
||||
if result["error"] is not None:
|
||||
self.log.debug("Error happened")
|
||||
self.errored = True
|
||||
|
||||
self.log.debug("Pair processed")
|
||||
self.was_processed.emit(result)
|
||||
|
||||
except Exception:
|
||||
# TODO this should be handled much differently
|
||||
# TODO emit crash signal to show message box with traceback
|
||||
exc_type, exc_msg, exc_tb = sys.exc_info()
|
||||
traceback.print_exception(exc_type, exc_msg, exc_tb)
|
||||
self.is_running = False
|
||||
self.was_stopped.emit()
|
||||
except Exception as exc:
|
||||
self.log.warning(
|
||||
"Unexpected exception during `on_process` happened",
|
||||
exc_info=True
|
||||
)
|
||||
exc_msg = str(exc)
|
||||
return util.defer(
|
||||
500, lambda: on_unexpected_error(error=exc_msg)
|
||||
)
|
||||
|
|
@ -396,6 +413,10 @@ class Controller(QtCore.QObject):
|
|||
util.defer(10, on_next)
|
||||
|
||||
def on_unexpected_error(error):
|
||||
# TODO this should be handled much differently
|
||||
# TODO emit crash signal to show message box with traceback?
|
||||
self.is_running = False
|
||||
self.was_stopped.emit()
|
||||
util.u_print(u"An unexpected error occurred:\n %s" % error)
|
||||
return util.defer(500, on_finished)
|
||||
|
||||
|
|
@ -446,9 +467,9 @@ class Controller(QtCore.QObject):
|
|||
try:
|
||||
callback(instance, old_value, new_value)
|
||||
except Exception:
|
||||
print(
|
||||
self.log.warning(
|
||||
"Callback for `instanceToggled` crashed. {}".format(
|
||||
os.path.abspath(inspect.getfile(callback))
|
||||
)
|
||||
),
|
||||
exc_info=True
|
||||
)
|
||||
traceback.print_exception(*sys.exc_info())
|
||||
|
|
|
|||
|
|
@ -266,7 +266,7 @@ class DropDataFrame(QtWidgets.QFrame):
|
|||
def load_data_with_probe(self, filepath):
|
||||
ffprobe_path = pype.lib.get_ffmpeg_tool_path("ffprobe")
|
||||
args = [
|
||||
ffprobe_path,
|
||||
"\"{}\"".format(ffprobe_path),
|
||||
'-v', 'quiet',
|
||||
'-print_format json',
|
||||
'-show_format',
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
__version__ = "2.13.0"
|
||||
__version__ = "2.13.4"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue