mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Merge branch 'develop' into feature/OP-3419_Move-editorial-logic-to-pipeline
This commit is contained in:
commit
08715b59c1
7 changed files with 177 additions and 46 deletions
|
|
@ -1,4 +1,5 @@
|
|||
import re
|
||||
from types import NoneType
|
||||
import pyblish
|
||||
import openpype.hosts.flame.api as opfapi
|
||||
from openpype.hosts.flame.otio import flame_export
|
||||
|
|
@ -78,6 +79,12 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin):
|
|||
marker_data["handleEnd"]
|
||||
)
|
||||
|
||||
# make sure there is not NoneType rather 0
|
||||
if isinstance(head, NoneType):
|
||||
head = 0
|
||||
if isinstance(tail, NoneType):
|
||||
tail = 0
|
||||
|
||||
# make sure value is absolute
|
||||
if head != 0:
|
||||
head = abs(head)
|
||||
|
|
@ -128,7 +135,8 @@ class CollectTimelineInstances(pyblish.api.ContextPlugin):
|
|||
"flameAddTasks": self.add_tasks,
|
||||
"tasks": {
|
||||
task["name"]: {"type": task["type"]}
|
||||
for task in self.add_tasks}
|
||||
for task in self.add_tasks},
|
||||
"representations": []
|
||||
})
|
||||
self.log.debug("__ inst_data: {}".format(pformat(inst_data)))
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ class ExtractSubsetResources(openpype.api.Extractor):
|
|||
hosts = ["flame"]
|
||||
|
||||
# plugin defaults
|
||||
keep_original_representation = False
|
||||
|
||||
default_presets = {
|
||||
"thumbnail": {
|
||||
"active": True,
|
||||
|
|
@ -45,7 +47,9 @@ class ExtractSubsetResources(openpype.api.Extractor):
|
|||
export_presets_mapping = {}
|
||||
|
||||
def process(self, instance):
|
||||
if "representations" not in instance.data:
|
||||
|
||||
if not self.keep_original_representation:
|
||||
# remove previeous representation if not needed
|
||||
instance.data["representations"] = []
|
||||
|
||||
# flame objects
|
||||
|
|
@ -82,7 +86,11 @@ class ExtractSubsetResources(openpype.api.Extractor):
|
|||
# add default preset type for thumbnail and reviewable video
|
||||
# update them with settings and override in case the same
|
||||
# are found in there
|
||||
export_presets = deepcopy(self.default_presets)
|
||||
_preset_keys = [k.split('_')[0] for k in self.export_presets_mapping]
|
||||
export_presets = {
|
||||
k: v for k, v in deepcopy(self.default_presets).items()
|
||||
if k not in _preset_keys
|
||||
}
|
||||
export_presets.update(self.export_presets_mapping)
|
||||
|
||||
# loop all preset names and
|
||||
|
|
@ -218,9 +226,14 @@ class ExtractSubsetResources(openpype.api.Extractor):
|
|||
opfapi.export_clip(
|
||||
export_dir_path, exporting_clip, preset_path, **export_kwargs)
|
||||
|
||||
repr_name = unique_name
|
||||
# make sure only first segment is used if underscore in name
|
||||
# HACK: `ftrackreview_withLUT` will result only in `ftrackreview`
|
||||
repr_name = unique_name.split("_")[0]
|
||||
if (
|
||||
"thumbnail" in unique_name
|
||||
or "ftrackreview" in unique_name
|
||||
):
|
||||
repr_name = unique_name.split("_")[0]
|
||||
|
||||
# create representation data
|
||||
representation_data = {
|
||||
|
|
@ -259,7 +272,7 @@ class ExtractSubsetResources(openpype.api.Extractor):
|
|||
if os.path.splitext(f)[-1] == ".mov"
|
||||
]
|
||||
# then try if thumbnail is not in unique name
|
||||
or unique_name == "thumbnail"
|
||||
or repr_name == "thumbnail"
|
||||
):
|
||||
representation_data["files"] = files.pop()
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -6,13 +6,12 @@ import logging
|
|||
import six
|
||||
import platform
|
||||
|
||||
from openpype.client import get_project
|
||||
from openpype.settings import get_project_settings
|
||||
|
||||
from .anatomy import Anatomy
|
||||
from .profiles_filtering import filter_profiles
|
||||
|
||||
import avalon.api
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -204,9 +203,7 @@ def concatenate_splitted_paths(split_paths, anatomy):
|
|||
|
||||
|
||||
def get_format_data(anatomy):
|
||||
dbcon = avalon.api.AvalonMongoDB()
|
||||
dbcon.Session["AVALON_PROJECT"] = anatomy.project_name
|
||||
project_doc = dbcon.find_one({"type": "project"})
|
||||
project_doc = get_project(anatomy.project_name, fields=["data.code"])
|
||||
project_code = project_doc["data"]["code"]
|
||||
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import attr
|
||||
from bson.objectid import ObjectId
|
||||
import datetime
|
||||
|
||||
from Qt import QtCore
|
||||
from Qt.QtCore import Qt
|
||||
|
|
@ -413,6 +414,23 @@ class _SyncRepresentationModel(QtCore.QAbstractTableModel):
|
|||
return index
|
||||
return None
|
||||
|
||||
def _convert_date(self, date_value, current_date):
|
||||
"""Converts 'date_value' to string.
|
||||
|
||||
Value of date_value might contain date in the future, used for nicely
|
||||
sort queued items next to last downloaded.
|
||||
"""
|
||||
try:
|
||||
converted_date = None
|
||||
# ignore date in the future - for sorting only
|
||||
if date_value and date_value < current_date:
|
||||
converted_date = date_value.strftime("%Y%m%dT%H%M%SZ")
|
||||
except (AttributeError, TypeError):
|
||||
# ignore unparseable values
|
||||
pass
|
||||
|
||||
return converted_date
|
||||
|
||||
|
||||
class SyncRepresentationSummaryModel(_SyncRepresentationModel):
|
||||
"""
|
||||
|
|
@ -560,7 +578,7 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel):
|
|||
remote_provider = lib.translate_provider_for_icon(self.sync_server,
|
||||
self.project,
|
||||
remote_site)
|
||||
|
||||
current_date = datetime.datetime.now()
|
||||
for repre in result.get("paginatedResults"):
|
||||
files = repre.get("files", [])
|
||||
if isinstance(files, dict): # aggregate returns dictionary
|
||||
|
|
@ -570,14 +588,10 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel):
|
|||
if not files:
|
||||
continue
|
||||
|
||||
local_updated = remote_updated = None
|
||||
if repre.get('updated_dt_local'):
|
||||
local_updated = \
|
||||
repre.get('updated_dt_local').strftime("%Y%m%dT%H%M%SZ")
|
||||
|
||||
if repre.get('updated_dt_remote'):
|
||||
remote_updated = \
|
||||
repre.get('updated_dt_remote').strftime("%Y%m%dT%H%M%SZ")
|
||||
local_updated = self._convert_date(repre.get('updated_dt_local'),
|
||||
current_date)
|
||||
remote_updated = self._convert_date(repre.get('updated_dt_remote'),
|
||||
current_date)
|
||||
|
||||
avg_progress_remote = lib.convert_progress(
|
||||
repre.get('avg_progress_remote', '0'))
|
||||
|
|
@ -645,6 +659,8 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel):
|
|||
if limit == 0:
|
||||
limit = SyncRepresentationSummaryModel.PAGE_SIZE
|
||||
|
||||
# replace null with value in the future for better sorting
|
||||
dummy_max_date = datetime.datetime(2099, 1, 1)
|
||||
aggr = [
|
||||
{"$match": self.get_match_part()},
|
||||
{'$unwind': '$files'},
|
||||
|
|
@ -687,7 +703,7 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel):
|
|||
{'$cond': [
|
||||
{'$size': "$order_remote.last_failed_dt"},
|
||||
"$order_remote.last_failed_dt",
|
||||
[]
|
||||
[dummy_max_date]
|
||||
]}
|
||||
]}},
|
||||
'updated_dt_local': {'$first': {
|
||||
|
|
@ -696,7 +712,7 @@ class SyncRepresentationSummaryModel(_SyncRepresentationModel):
|
|||
{'$cond': [
|
||||
{'$size': "$order_local.last_failed_dt"},
|
||||
"$order_local.last_failed_dt",
|
||||
[]
|
||||
[dummy_max_date]
|
||||
]}
|
||||
]}},
|
||||
'files_size': {'$ifNull': ["$files.size", 0]},
|
||||
|
|
@ -1039,6 +1055,7 @@ class SyncRepresentationDetailModel(_SyncRepresentationModel):
|
|||
self.project,
|
||||
remote_site)
|
||||
|
||||
current_date = datetime.datetime.now()
|
||||
for repre in result.get("paginatedResults"):
|
||||
# log.info("!!! repre:: {}".format(repre))
|
||||
files = repre.get("files", [])
|
||||
|
|
@ -1046,16 +1063,12 @@ class SyncRepresentationDetailModel(_SyncRepresentationModel):
|
|||
files = [files]
|
||||
|
||||
for file in files:
|
||||
local_updated = remote_updated = None
|
||||
if repre.get('updated_dt_local'):
|
||||
local_updated = \
|
||||
repre.get('updated_dt_local').strftime(
|
||||
"%Y%m%dT%H%M%SZ")
|
||||
|
||||
if repre.get('updated_dt_remote'):
|
||||
remote_updated = \
|
||||
repre.get('updated_dt_remote').strftime(
|
||||
"%Y%m%dT%H%M%SZ")
|
||||
local_updated = self._convert_date(
|
||||
repre.get('updated_dt_local'),
|
||||
current_date)
|
||||
remote_updated = self._convert_date(
|
||||
repre.get('updated_dt_remote'),
|
||||
current_date)
|
||||
|
||||
remote_progress = lib.convert_progress(
|
||||
repre.get('progress_remote', '0'))
|
||||
|
|
@ -1104,6 +1117,7 @@ class SyncRepresentationDetailModel(_SyncRepresentationModel):
|
|||
if limit == 0:
|
||||
limit = SyncRepresentationSummaryModel.PAGE_SIZE
|
||||
|
||||
dummy_max_date = datetime.datetime(2099, 1, 1)
|
||||
aggr = [
|
||||
{"$match": self.get_match_part()},
|
||||
{"$unwind": "$files"},
|
||||
|
|
@ -1147,7 +1161,7 @@ class SyncRepresentationDetailModel(_SyncRepresentationModel):
|
|||
'$cond': [
|
||||
{'$size': "$order_remote.last_failed_dt"},
|
||||
"$order_remote.last_failed_dt",
|
||||
[]
|
||||
[dummy_max_date]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -1160,7 +1174,7 @@ class SyncRepresentationDetailModel(_SyncRepresentationModel):
|
|||
'$cond': [
|
||||
{'$size': "$order_local.last_failed_dt"},
|
||||
"$order_local.last_failed_dt",
|
||||
[]
|
||||
[dummy_max_date]
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1418,3 +1418,6 @@ InViewButton, InViewButton:disabled {
|
|||
InViewButton:hover {
|
||||
background: rgba(255, 255, 255, 37);
|
||||
}
|
||||
SupportLabel {
|
||||
color: {color:font-disabled};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -977,7 +977,12 @@ class CreateDialog(QtWidgets.QDialog):
|
|||
elif variant:
|
||||
self.variant_hints_menu.addAction(variant)
|
||||
|
||||
self.variant_input.setText(default_variant or "Main")
|
||||
variant_text = default_variant or "Main"
|
||||
# Make sure subset name is updated to new plugin
|
||||
if variant_text == self.variant_input.text():
|
||||
self._on_variant_change()
|
||||
else:
|
||||
self.variant_input.setText(variant_text)
|
||||
|
||||
def _on_variant_widget_resize(self):
|
||||
self.variant_hints_btn.setFixedHeight(self.variant_input.height())
|
||||
|
|
|
|||
|
|
@ -26,26 +26,110 @@ IS_SEQUENCE_ROLE = QtCore.Qt.UserRole + 7
|
|||
EXT_ROLE = QtCore.Qt.UserRole + 8
|
||||
|
||||
|
||||
class SupportLabel(QtWidgets.QLabel):
|
||||
pass
|
||||
|
||||
|
||||
class DropEmpty(QtWidgets.QWidget):
|
||||
_drop_enabled_text = "Drag & Drop\n(drop files here)"
|
||||
_empty_extensions = "Any file"
|
||||
|
||||
def __init__(self, parent):
|
||||
def __init__(self, single_item, allow_sequences, parent):
|
||||
super(DropEmpty, self).__init__(parent)
|
||||
label_widget = QtWidgets.QLabel(self._drop_enabled_text, self)
|
||||
label_widget.setAlignment(QtCore.Qt.AlignCenter)
|
||||
|
||||
label_widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
drop_label_widget = QtWidgets.QLabel("Drag & Drop files here", self)
|
||||
|
||||
layout = QtWidgets.QHBoxLayout(self)
|
||||
items_label_widget = SupportLabel(self)
|
||||
items_label_widget.setWordWrap(True)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addSpacing(10)
|
||||
layout.addSpacing(20)
|
||||
layout.addWidget(
|
||||
label_widget,
|
||||
alignment=QtCore.Qt.AlignCenter
|
||||
drop_label_widget, 0, alignment=QtCore.Qt.AlignCenter
|
||||
)
|
||||
layout.addSpacing(30)
|
||||
layout.addStretch(1)
|
||||
layout.addWidget(
|
||||
items_label_widget, 0, alignment=QtCore.Qt.AlignCenter
|
||||
)
|
||||
layout.addSpacing(10)
|
||||
|
||||
self._label_widget = label_widget
|
||||
for widget in (
|
||||
drop_label_widget,
|
||||
items_label_widget,
|
||||
):
|
||||
widget.setAlignment(QtCore.Qt.AlignCenter)
|
||||
widget.setAttribute(QtCore.Qt.WA_TranslucentBackground)
|
||||
|
||||
self._single_item = single_item
|
||||
self._allow_sequences = allow_sequences
|
||||
self._allowed_extensions = set()
|
||||
self._allow_folders = None
|
||||
|
||||
self._drop_label_widget = drop_label_widget
|
||||
self._items_label_widget = items_label_widget
|
||||
|
||||
self.set_allow_folders(False)
|
||||
|
||||
def set_extensions(self, extensions):
|
||||
if extensions:
|
||||
extensions = {
|
||||
ext.replace(".", "")
|
||||
for ext in extensions
|
||||
}
|
||||
if extensions == self._allowed_extensions:
|
||||
return
|
||||
self._allowed_extensions = extensions
|
||||
|
||||
self._update_items_label()
|
||||
|
||||
def set_allow_folders(self, allowed):
|
||||
if self._allow_folders == allowed:
|
||||
return
|
||||
|
||||
self._allow_folders = allowed
|
||||
self._update_items_label()
|
||||
|
||||
def _update_items_label(self):
|
||||
allowed_items = []
|
||||
if self._allow_folders:
|
||||
allowed_items.append("folder")
|
||||
|
||||
if self._allowed_extensions:
|
||||
allowed_items.append("file")
|
||||
if self._allow_sequences:
|
||||
allowed_items.append("sequence")
|
||||
|
||||
if not self._single_item:
|
||||
allowed_items = [item + "s" for item in allowed_items]
|
||||
|
||||
if not allowed_items:
|
||||
self._items_label_widget.setText(
|
||||
"It is not allowed to add anything here!"
|
||||
)
|
||||
return
|
||||
|
||||
items_label = "Multiple "
|
||||
if self._single_item:
|
||||
items_label = "Single "
|
||||
|
||||
if len(allowed_items) == 1:
|
||||
allowed_items_label = allowed_items[0]
|
||||
elif len(allowed_items) == 2:
|
||||
allowed_items_label = " or ".join(allowed_items)
|
||||
else:
|
||||
last_item = allowed_items.pop(-1)
|
||||
new_last_item = " or ".join(last_item, allowed_items.pop(-1))
|
||||
allowed_items.append(new_last_item)
|
||||
allowed_items_label = ", ".join(allowed_items)
|
||||
|
||||
items_label += allowed_items_label
|
||||
if self._allowed_extensions:
|
||||
items_label += " of\n{}".format(
|
||||
", ".join(sorted(self._allowed_extensions))
|
||||
)
|
||||
|
||||
self._items_label_widget.setText(items_label)
|
||||
|
||||
def paintEvent(self, event):
|
||||
super(DropEmpty, self).paintEvent(event)
|
||||
|
|
@ -188,7 +272,12 @@ class FilesProxyModel(QtCore.QSortFilterProxyModel):
|
|||
|
||||
def set_allowed_extensions(self, extensions=None):
|
||||
if extensions is not None:
|
||||
extensions = set(extensions)
|
||||
_extensions = set()
|
||||
for ext in set(extensions):
|
||||
if not ext.startswith("."):
|
||||
ext = ".{}".format(ext)
|
||||
_extensions.add(ext.lower())
|
||||
extensions = _extensions
|
||||
|
||||
if self._allowed_extensions != extensions:
|
||||
self._allowed_extensions = extensions
|
||||
|
|
@ -444,7 +533,7 @@ class FilesWidget(QtWidgets.QFrame):
|
|||
super(FilesWidget, self).__init__(parent)
|
||||
self.setAcceptDrops(True)
|
||||
|
||||
empty_widget = DropEmpty(self)
|
||||
empty_widget = DropEmpty(single_item, allow_sequences, self)
|
||||
|
||||
files_model = FilesModel(single_item, allow_sequences)
|
||||
files_proxy_model = FilesProxyModel()
|
||||
|
|
@ -519,6 +608,8 @@ class FilesWidget(QtWidgets.QFrame):
|
|||
def set_filters(self, folders_allowed, exts_filter):
|
||||
self._files_proxy_model.set_allow_folders(folders_allowed)
|
||||
self._files_proxy_model.set_allowed_extensions(exts_filter)
|
||||
self._empty_widget.set_extensions(exts_filter)
|
||||
self._empty_widget.set_allow_folders(folders_allowed)
|
||||
|
||||
def _on_rows_inserted(self, parent_index, start_row, end_row):
|
||||
for row in range(start_row, end_row + 1):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue