mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-25 05:14:40 +01:00
feat(resolve): wip integration
workio, pipeline and basic avalon methods, menu,
This commit is contained in:
parent
1dc624cdc6
commit
341379e546
22 changed files with 1014 additions and 354 deletions
|
|
@ -2,7 +2,7 @@ import os
|
|||
import traceback
|
||||
from pype.lib import PypeHook
|
||||
from pypeapp import Logger
|
||||
from pype.resolve import lib as rlib
|
||||
from pype.resolve import utils
|
||||
|
||||
|
||||
class ResolvePrelaunch(PypeHook):
|
||||
|
|
@ -27,14 +27,15 @@ class ResolvePrelaunch(PypeHook):
|
|||
env = os.environ
|
||||
|
||||
# making sure pyton 3.6 is installed at provided path
|
||||
py36_dir = os.path.normpath(env.get("PYTHON36_RES", ""))
|
||||
py36_dir = os.path.normpath(env.get("PYTHON36_RESOLVE", ""))
|
||||
assert os.path.isdir(py36_dir), (
|
||||
"Python 3.6 is not installed at the provided folder path. Either "
|
||||
"make sure the `environments\resolve.json` is having correctly set "
|
||||
"`PYTHON36_RES` or make sure Python 3.6 is installed in given path."
|
||||
f"\nPYTHON36_RES: `{py36_dir}`"
|
||||
"`PYTHON36_RESOLVE` or make sure Python 3.6 is installed in given path."
|
||||
f"\nPYTHON36_RESOLVE: `{py36_dir}`"
|
||||
)
|
||||
env["PYTHON36_RES"] = py36_dir
|
||||
self.log.info(f"Path to Resolve Python folder: `{py36_dir}`...")
|
||||
env["PYTHON36_RESOLVE"] = py36_dir
|
||||
|
||||
# setting utility scripts dir for scripts syncing
|
||||
us_dir = os.path.normpath(env.get("RESOLVE_UTILITY_SCRIPTS_DIR", ""))
|
||||
|
|
@ -59,6 +60,6 @@ class ResolvePrelaunch(PypeHook):
|
|||
|
||||
else:
|
||||
# Resolve Setup integration
|
||||
rlib.setup(env)
|
||||
utils.setup(env)
|
||||
|
||||
return True
|
||||
|
|
|
|||
17
pype/plugins/resolve/publish/collect_host.py
Normal file
17
pype/plugins/resolve/publish/collect_host.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import pyblish.api
|
||||
from python_get_resolve import GetResolve
|
||||
|
||||
|
||||
class CollectProject(pyblish.api.ContextPlugin):
|
||||
"""Collect Project object"""
|
||||
|
||||
order = pyblish.api.CollectorOrder - 0.1
|
||||
label = "Collect Project"
|
||||
hosts = ["resolve"]
|
||||
|
||||
def process(self, context):
|
||||
resolve = GetResolve()
|
||||
PM = resolve.GetProjectManager()
|
||||
P = PM.GetCurrentProject()
|
||||
|
||||
self.log.info(P.GetName())
|
||||
|
|
@ -1,71 +1,47 @@
|
|||
import os
|
||||
from avalon import api as avalon
|
||||
from pyblish import api as pyblish
|
||||
from pypeapp import Logger
|
||||
|
||||
|
||||
from .lib import (
|
||||
setup,
|
||||
reload_pipeline,
|
||||
from .pipeline import (
|
||||
install,
|
||||
uninstall,
|
||||
ls,
|
||||
# LOAD_PATH,
|
||||
# CREATE_PATH,
|
||||
PUBLISH_PATH
|
||||
containerise,
|
||||
reload_pipeline,
|
||||
publish,
|
||||
launch_workfiles_app
|
||||
)
|
||||
|
||||
from .utils import (
|
||||
setup,
|
||||
get_resolve_module
|
||||
)
|
||||
|
||||
from .workio import (
|
||||
open_file,
|
||||
save_file,
|
||||
current_file,
|
||||
has_unsaved_changes,
|
||||
file_extensions,
|
||||
work_root
|
||||
)
|
||||
|
||||
# from .lib import (
|
||||
#
|
||||
# )
|
||||
|
||||
__all__ = [
|
||||
"setup",
|
||||
"install",
|
||||
"uninstall",
|
||||
"ls",
|
||||
"containerise",
|
||||
"reload_pipeline",
|
||||
"ls"
|
||||
"publish",
|
||||
"launch_workfiles_app",
|
||||
|
||||
"setup",
|
||||
"get_resolve_module",
|
||||
|
||||
"open_file",
|
||||
"save_file",
|
||||
"current_file",
|
||||
"has_unsaved_changes",
|
||||
"file_extensions",
|
||||
"work_root"
|
||||
]
|
||||
|
||||
log = Logger().get_logger(__name__, "resolve")
|
||||
|
||||
|
||||
def install():
|
||||
"""Install resolve-specific functionality of avalon-core.
|
||||
|
||||
This is where you install menus and register families, data
|
||||
and loaders into resolve.
|
||||
|
||||
It is called automatically when installing via `api.install(resolve)`.
|
||||
|
||||
See the Maya equivalent for inspiration on how to implement this.
|
||||
|
||||
"""
|
||||
|
||||
# Disable all families except for the ones we explicitly want to see
|
||||
family_states = [
|
||||
"imagesequence",
|
||||
"mov"
|
||||
]
|
||||
avalon.data["familiesStateDefault"] = False
|
||||
avalon.data["familiesStateToggled"] = family_states
|
||||
|
||||
log.info("pype.resolve installed")
|
||||
|
||||
pyblish.register_host("resolve")
|
||||
pyblish.register_plugin_path(PUBLISH_PATH)
|
||||
log.info("Registering Premiera plug-ins..")
|
||||
|
||||
# avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
# avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
|
||||
|
||||
def uninstall():
|
||||
"""Uninstall all tha was installed
|
||||
|
||||
This is where you undo everything that was done in `install()`.
|
||||
That means, removing menus, deregistering families and data
|
||||
and everything. It should be as though `install()` was never run,
|
||||
because odds are calling this function means the user is interested
|
||||
in re-installing shortly afterwards. If, for example, he has been
|
||||
modifying the menu or registered families.
|
||||
|
||||
"""
|
||||
pyblish.deregister_host("resolve")
|
||||
pyblish.deregister_plugin_path(PUBLISH_PATH)
|
||||
log.info("Deregistering Premiera plug-ins..")
|
||||
|
||||
# avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
# avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
|
|
|
|||
53
pype/resolve/action.py
Normal file
53
pype/resolve/action.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# absolute_import is needed to counter the `module has no cmds error` in Maya
|
||||
from __future__ import absolute_import
|
||||
|
||||
import pyblish.api
|
||||
|
||||
|
||||
from ..action import get_errored_instances_from_context
|
||||
|
||||
|
||||
class SelectInvalidAction(pyblish.api.Action):
|
||||
"""Select invalid clips in Resolve timeline when plug-in failed.
|
||||
|
||||
To retrieve the invalid nodes this assumes a static `get_invalid()`
|
||||
method is available on the plugin.
|
||||
|
||||
"""
|
||||
label = "Select invalid"
|
||||
on = "failed" # This action is only available on a failed plug-in
|
||||
icon = "search" # Icon from Awesome Icon
|
||||
|
||||
def process(self, context, plugin):
|
||||
|
||||
try:
|
||||
from pype.resolve.utils import get_resolve_module
|
||||
resolve = get_resolve_module()
|
||||
except ImportError:
|
||||
raise ImportError("Current host is not Resolve")
|
||||
|
||||
errored_instances = get_errored_instances_from_context(context)
|
||||
|
||||
# Apply pyblish.logic to get the instances for the plug-in
|
||||
instances = pyblish.api.instances_by_plugin(errored_instances, plugin)
|
||||
|
||||
# Get the invalid nodes for the plug-ins
|
||||
self.log.info("Finding invalid clips..")
|
||||
invalid = list()
|
||||
for instance in instances:
|
||||
invalid_nodes = plugin.get_invalid(instance)
|
||||
if invalid_nodes:
|
||||
if isinstance(invalid_nodes, (list, tuple)):
|
||||
invalid.extend(invalid_nodes)
|
||||
else:
|
||||
self.log.warning("Plug-in returned to be invalid, "
|
||||
"but has no selectable nodes.")
|
||||
|
||||
# Ensure unique (process each node only once)
|
||||
invalid = list(set(invalid))
|
||||
|
||||
if invalid:
|
||||
self.log.info("Selecting invalid nodes: %s" % ", ".join(invalid))
|
||||
# TODO: select resolve timeline track items in current timeline
|
||||
else:
|
||||
self.log.info("No invalid nodes found.")
|
||||
|
|
@ -1,109 +0,0 @@
|
|||
import os
|
||||
import sys
|
||||
import shutil
|
||||
|
||||
from avalon import api
|
||||
from pype.widgets.message_window import message
|
||||
from pypeapp import Logger
|
||||
|
||||
log = Logger().get_logger(__name__, "resolve")
|
||||
|
||||
self = sys.modules[__name__]
|
||||
|
||||
AVALON_CONFIG = os.environ["AVALON_CONFIG"]
|
||||
PARENT_DIR = os.path.dirname(__file__)
|
||||
PACKAGE_DIR = os.path.dirname(PARENT_DIR)
|
||||
PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins")
|
||||
|
||||
self.UTILITY_SCRIPTS = os.path.join(PARENT_DIR, "resolve_utility_scripts")
|
||||
|
||||
self.PUBLISH_PATH = os.path.join(
|
||||
PLUGINS_DIR, "resolve", "publish"
|
||||
).replace("\\", "/")
|
||||
|
||||
if os.getenv("PUBLISH_PATH", None):
|
||||
if self.PUBLISH_PATH not in os.environ["PUBLISH_PATH"]:
|
||||
os.environ["PUBLISH_PATH"] = os.pathsep.join(
|
||||
os.environ["PUBLISH_PATH"].split(os.pathsep) +
|
||||
[self.PUBLISH_PATH]
|
||||
)
|
||||
else:
|
||||
os.environ["PUBLISH_PATH"] = self.PUBLISH_PATH
|
||||
|
||||
|
||||
def ls():
|
||||
pass
|
||||
|
||||
|
||||
def sync_utility_scripts(env=None):
|
||||
""" Synchronizing basic utlility scripts for resolve.
|
||||
|
||||
To be able to run scripts from inside `Resolve/Workspace/Scripts` menu
|
||||
all scripts has to be accessible from defined folder.
|
||||
"""
|
||||
if not env:
|
||||
env = os.environ
|
||||
|
||||
us_dir = env.get("RESOLVE_UTILITY_SCRIPTS_DIR", "")
|
||||
scripts = os.listdir(self.UTILITY_SCRIPTS)
|
||||
|
||||
log.info(f"Utility Scripts Dir: `{self.UTILITY_SCRIPTS}`")
|
||||
log.info(f"Utility Scripts: `{scripts}`")
|
||||
|
||||
# make sure no script file is in folder
|
||||
if next((s for s in os.listdir(us_dir)), None):
|
||||
for s in os.listdir(us_dir):
|
||||
path = os.path.join(us_dir, s)
|
||||
log.info(f"Removing `{path}`...")
|
||||
os.remove(path)
|
||||
|
||||
# copy scripts into Resolve's utility scripts dir
|
||||
for s in scripts:
|
||||
src = os.path.join(self.UTILITY_SCRIPTS, s)
|
||||
dst = os.path.join(us_dir, s)
|
||||
log.info(f"Copying `{src}` to `{dst}`...")
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
|
||||
def reload_pipeline():
|
||||
"""Attempt to reload pipeline at run-time.
|
||||
|
||||
CAUTION: This is primarily for development and debugging purposes.
|
||||
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import pype.resolve
|
||||
|
||||
api.uninstall()
|
||||
|
||||
for module in ("avalon.io",
|
||||
"avalon.lib",
|
||||
"avalon.pipeline",
|
||||
"avalon.api",
|
||||
"avalon.tools",
|
||||
|
||||
"{}".format(AVALON_CONFIG),
|
||||
"{}.resolve".format(AVALON_CONFIG),
|
||||
"{}.resolve.lib".format(AVALON_CONFIG)
|
||||
):
|
||||
log.info("Reloading module: {}...".format(module))
|
||||
try:
|
||||
module = importlib.import_module(module)
|
||||
importlib.reload(module)
|
||||
except Exception as e:
|
||||
log.warning("Cannot reload module: {}".format(e))
|
||||
|
||||
api.install(pype.resolve)
|
||||
|
||||
|
||||
def setup(env=None):
|
||||
""" Running wrapper
|
||||
"""
|
||||
if not env:
|
||||
env = os.environ
|
||||
|
||||
# synchronize resolve utility scripts
|
||||
sync_utility_scripts(env)
|
||||
|
||||
log.info("Resolve Pype wrapper has been installed")
|
||||
133
pype/resolve/menu.py
Normal file
133
pype/resolve/menu.py
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
import os
|
||||
import sys
|
||||
|
||||
from Qt import QtWidgets, QtCore
|
||||
|
||||
|
||||
def load_stylesheet():
|
||||
path = os.path.join(os.path.dirname(__file__), "menu_style.qss")
|
||||
if not os.path.exists(path):
|
||||
print("Unable to load stylesheet, file not found in resources")
|
||||
return ""
|
||||
|
||||
with open(path, "r") as file_stream:
|
||||
stylesheet = file_stream.read()
|
||||
return stylesheet
|
||||
|
||||
|
||||
class Spacer(QtWidgets.QWidget):
|
||||
def __init__(self, height, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
|
||||
self.setFixedHeight(height)
|
||||
|
||||
real_spacer = QtWidgets.QWidget(self)
|
||||
real_spacer.setObjectName("Spacer")
|
||||
real_spacer.setFixedHeight(int(height / 3))
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.addWidget(real_spacer)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
class PypeMenu(QtWidgets.QWidget):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
|
||||
self.setObjectName("PypeMenu")
|
||||
|
||||
self.setWindowFlags(
|
||||
QtCore.Qt.Window
|
||||
| QtCore.Qt.CustomizeWindowHint
|
||||
| QtCore.Qt.WindowTitleHint
|
||||
| QtCore.Qt.WindowCloseButtonHint
|
||||
| QtCore.Qt.WindowStaysOnTopHint
|
||||
)
|
||||
|
||||
self.setWindowTitle("Pype")
|
||||
workfiles_btn = QtWidgets.QPushButton("Workfiles", self)
|
||||
create_btn = QtWidgets.QPushButton("Create", self)
|
||||
publish_btn = QtWidgets.QPushButton("Publish", self)
|
||||
load_btn = QtWidgets.QPushButton("Load", self)
|
||||
inventory_btn = QtWidgets.QPushButton("Inventory", self)
|
||||
rename_btn = QtWidgets.QPushButton("Rename", self)
|
||||
set_colorspace_btn = QtWidgets.QPushButton(
|
||||
"Set colorspace from presets", self
|
||||
)
|
||||
reset_resolution_btn = QtWidgets.QPushButton(
|
||||
"Reset Resolution from peresets", self
|
||||
)
|
||||
reload_pipeline_btn = QtWidgets.QPushButton("Reload pipeline", self)
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(10, 10, 10, 10)
|
||||
|
||||
layout.addWidget(workfiles_btn)
|
||||
layout.addWidget(create_btn)
|
||||
layout.addWidget(publish_btn)
|
||||
layout.addWidget(load_btn)
|
||||
layout.addWidget(inventory_btn)
|
||||
|
||||
layout.addWidget(Spacer(20, self))
|
||||
|
||||
layout.addWidget(rename_btn)
|
||||
layout.addWidget(set_colorspace_btn)
|
||||
layout.addWidget(reset_resolution_btn)
|
||||
|
||||
layout.addWidget(Spacer(20, self))
|
||||
|
||||
layout.addWidget(reload_pipeline_btn)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
workfiles_btn.clicked.connect(self.on_reload_pipeline_clicked)
|
||||
create_btn.clicked.connect(self.on_create_clicked)
|
||||
publish_btn.clicked.connect(self.on_publish_clicked)
|
||||
load_btn.clicked.connect(self.on_load_clicked)
|
||||
inventory_btn.clicked.connect(self.on_inventory_clicked)
|
||||
rename_btn.clicked.connect(self.on_rename_clicked)
|
||||
set_colorspace_btn.clicked.connect(self.on_set_colorspace_clicked)
|
||||
reset_resolution_btn.clicked.connect(self.on_reset_resolution_clicked)
|
||||
reload_pipeline_btn.clicked.connect(self.on_reload_pipeline_clicked)
|
||||
|
||||
def on_workfile_clicked(self):
|
||||
print("Clicked Workfile")
|
||||
|
||||
def on_create_clicked(self):
|
||||
print("Clicked Create")
|
||||
|
||||
def on_publish_clicked(self):
|
||||
print("Clicked Publish")
|
||||
|
||||
def on_load_clicked(self):
|
||||
print("Clicked Load")
|
||||
|
||||
def on_inventory_clicked(self):
|
||||
print("Clicked Inventory")
|
||||
|
||||
def on_rename_clicked(self):
|
||||
print("Clicked Rename")
|
||||
|
||||
def on_set_colorspace_clicked(self):
|
||||
print("Clicked Set Colorspace")
|
||||
|
||||
def on_reset_resolution_clicked(self):
|
||||
print("Clicked Reset Resolution")
|
||||
|
||||
def on_reload_pipeline_clicked(self):
|
||||
print("Clicked Reload Pipeline")
|
||||
|
||||
|
||||
def launch_pype_menu():
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
|
||||
pype_menu = PypeMenu()
|
||||
|
||||
stylesheet = load_stylesheet()
|
||||
pype_menu.setStyleSheet(stylesheet)
|
||||
|
||||
pype_menu.show()
|
||||
|
||||
sys.exit(app.exec_())
|
||||
34
pype/resolve/menu_style.qss
Normal file
34
pype/resolve/menu_style.qss
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
QWidget {
|
||||
background-color: #3a3939;
|
||||
border-radius: 5;
|
||||
}
|
||||
|
||||
QPushButton {
|
||||
border: 1px solid #6d6d6d;
|
||||
background-color: #201f1f;
|
||||
color: #6d6d6d;
|
||||
padding: 5;
|
||||
}
|
||||
|
||||
QPushButton:focus {
|
||||
background-color: "#272525";
|
||||
}
|
||||
|
||||
QPushButton:pressed {
|
||||
background-color: "#686464";
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
QPushButton:hover {
|
||||
color: #d0d0d0;
|
||||
background-color: "#343232";
|
||||
}
|
||||
|
||||
#PypeMenu {
|
||||
border: 1px solid #333333;
|
||||
}
|
||||
|
||||
#Spacer {
|
||||
padding: 10;
|
||||
background-color: #464646;
|
||||
}
|
||||
184
pype/resolve/pipeline.py
Normal file
184
pype/resolve/pipeline.py
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
"""
|
||||
Basic avalon integration
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
from avalon.tools import workfiles
|
||||
from avalon import api as avalon
|
||||
from pyblish import api as pyblish
|
||||
from pypeapp import Logger
|
||||
|
||||
log = Logger().get_logger(__name__, "resolve")
|
||||
|
||||
# self = sys.modules[__name__]
|
||||
|
||||
AVALON_CONFIG = os.environ["AVALON_CONFIG"]
|
||||
PARENT_DIR = os.path.dirname(__file__)
|
||||
PACKAGE_DIR = os.path.dirname(PARENT_DIR)
|
||||
PLUGINS_DIR = os.path.join(PACKAGE_DIR, "plugins")
|
||||
|
||||
LOAD_PATH = os.path.join(PLUGINS_DIR, "resolve", "load")
|
||||
CREATE_PATH = os.path.join(PLUGINS_DIR, "resolve", "create")
|
||||
INVENTORY_PATH = os.path.join(PLUGINS_DIR, "resolve", "inventory")
|
||||
|
||||
PUBLISH_PATH = os.path.join(
|
||||
PLUGINS_DIR, "resolve", "publish"
|
||||
).replace("\\", "/")
|
||||
|
||||
AVALON_CONTAINERS = ":AVALON_CONTAINERS"
|
||||
# IS_HEADLESS = not hasattr(cmds, "about") or cmds.about(batch=True)
|
||||
|
||||
|
||||
def install():
|
||||
"""Install resolve-specific functionality of avalon-core.
|
||||
|
||||
This is where you install menus and register families, data
|
||||
and loaders into resolve.
|
||||
|
||||
It is called automatically when installing via `api.install(resolve)`.
|
||||
|
||||
See the Maya equivalent for inspiration on how to implement this.
|
||||
|
||||
"""
|
||||
from .menu import launch_pype_menu
|
||||
|
||||
# Disable all families except for the ones we explicitly want to see
|
||||
family_states = [
|
||||
"imagesequence",
|
||||
"mov"
|
||||
]
|
||||
avalon.data["familiesStateDefault"] = False
|
||||
avalon.data["familiesStateToggled"] = family_states
|
||||
|
||||
log.info("pype.resolve installed")
|
||||
|
||||
pyblish.register_host("resolve")
|
||||
pyblish.register_plugin_path(PUBLISH_PATH)
|
||||
log.info("Registering DaVinci Resovle plug-ins..")
|
||||
|
||||
avalon.register_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.register_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
avalon.register_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
|
||||
|
||||
# opening menu
|
||||
launch_pype_menu()
|
||||
|
||||
|
||||
def uninstall():
|
||||
"""Uninstall all tha was installed
|
||||
|
||||
This is where you undo everything that was done in `install()`.
|
||||
That means, removing menus, deregistering families and data
|
||||
and everything. It should be as though `install()` was never run,
|
||||
because odds are calling this function means the user is interested
|
||||
in re-installing shortly afterwards. If, for example, he has been
|
||||
modifying the menu or registered families.
|
||||
|
||||
"""
|
||||
pyblish.deregister_host("resolve")
|
||||
pyblish.deregister_plugin_path(PUBLISH_PATH)
|
||||
log.info("Deregistering DaVinci Resovle plug-ins..")
|
||||
|
||||
avalon.deregister_plugin_path(avalon.Loader, LOAD_PATH)
|
||||
avalon.deregister_plugin_path(avalon.Creator, CREATE_PATH)
|
||||
avalon.deregister_plugin_path(avalon.InventoryAction, INVENTORY_PATH)
|
||||
|
||||
|
||||
def containerise(obj,
|
||||
name,
|
||||
namespace,
|
||||
context,
|
||||
loader=None,
|
||||
data=None):
|
||||
"""Bundle Resolve's object into an assembly and imprint it with metadata
|
||||
|
||||
Containerisation enables a tracking of version, author and origin
|
||||
for loaded assets.
|
||||
|
||||
Arguments:
|
||||
obj (obj): Resolve's object to imprint as container
|
||||
name (str): Name of resulting assembly
|
||||
namespace (str): Namespace under which to host container
|
||||
context (dict): Asset information
|
||||
loader (str, optional): Name of node used to produce this container.
|
||||
|
||||
Returns:
|
||||
obj (obj): containerised object
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def ls():
|
||||
"""List available containers.
|
||||
|
||||
This function is used by the Container Manager in Nuke. You'll
|
||||
need to implement a for-loop that then *yields* one Container at
|
||||
a time.
|
||||
|
||||
See the `container.json` schema for details on how it should look,
|
||||
and the Maya equivalent, which is in `avalon.maya.pipeline`
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def parse_container(container):
|
||||
"""Return the container node's full container data.
|
||||
|
||||
Args:
|
||||
container (str): A container node name.
|
||||
|
||||
Returns:
|
||||
dict: The container schema data for this container node.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
def launch_workfiles_app(*args):
|
||||
workdir = os.environ["AVALON_WORKDIR"]
|
||||
workfiles.show(workdir)
|
||||
|
||||
|
||||
def reload_pipeline():
|
||||
"""Attempt to reload pipeline at run-time.
|
||||
|
||||
CAUTION: This is primarily for development and debugging purposes.
|
||||
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import pype.resolve
|
||||
|
||||
avalon.uninstall()
|
||||
|
||||
# get avalon config name
|
||||
config = os.getenv("AVALON_CONFIG", "pype")
|
||||
|
||||
for module in ("avalon.io",
|
||||
"avalon.lib",
|
||||
"avalon.pipeline",
|
||||
"avalon.api",
|
||||
"avalon.tools",
|
||||
|
||||
"{}".format(config),
|
||||
"{}.resolve".format(config),
|
||||
"{}.resolve.lib".format(config),
|
||||
"{}.resolve.menu".format(config),
|
||||
"{}.resolve.plugin".format(config),
|
||||
"{}.resolve.pipeline".format(config)
|
||||
):
|
||||
log.info("Reloading module: {}...".format(module))
|
||||
try:
|
||||
module = importlib.import_module(module)
|
||||
importlib.reload(module)
|
||||
except Exception as e:
|
||||
log.warning("Cannot reload module: {}".format(e))
|
||||
|
||||
avalon.install(pype.resolve)
|
||||
|
||||
|
||||
def publish(parent):
|
||||
"""Shorthand to publish from within host"""
|
||||
from avalon.tools import publish
|
||||
return publish.show(parent)
|
||||
75
pype/resolve/plugin.py
Normal file
75
pype/resolve/plugin.py
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
from avalon import api
|
||||
from pype.resolve import lib as drlib
|
||||
from avalon.vendor import qargparse
|
||||
|
||||
|
||||
def get_reference_node_parents(ref):
|
||||
"""Return all parent reference nodes of reference node
|
||||
|
||||
Args:
|
||||
ref (str): reference node.
|
||||
|
||||
Returns:
|
||||
list: The upstream parent reference nodes.
|
||||
|
||||
"""
|
||||
parents = []
|
||||
return parents
|
||||
|
||||
|
||||
class SequenceLoader(api.Loader):
|
||||
"""A basic SequenceLoader for Resolve
|
||||
|
||||
This will implement the basic behavior for a loader to inherit from that
|
||||
will containerize the reference and will implement the `remove` and
|
||||
`update` logic.
|
||||
|
||||
"""
|
||||
|
||||
options = [
|
||||
qargparse.Toggle(
|
||||
"handles",
|
||||
label="Include handles",
|
||||
default=0,
|
||||
help="Load with handles or without?"
|
||||
),
|
||||
qargparse.Choice(
|
||||
"load_to",
|
||||
label="Where to load clips",
|
||||
items=[
|
||||
"Current timeline",
|
||||
"New timeline"
|
||||
],
|
||||
default=0,
|
||||
help="Where do you want clips to be loaded?"
|
||||
),
|
||||
qargparse.Choice(
|
||||
"load_how",
|
||||
label="How to load clips",
|
||||
items=[
|
||||
"original timing",
|
||||
"sequential in order"
|
||||
],
|
||||
default=0,
|
||||
help="Would you like to place it at orignal timing?"
|
||||
)
|
||||
]
|
||||
|
||||
def load(
|
||||
self,
|
||||
context,
|
||||
name=None,
|
||||
namespace=None,
|
||||
options=None
|
||||
):
|
||||
pass
|
||||
|
||||
def update(self, container, representation):
|
||||
"""Update an existing `container`
|
||||
"""
|
||||
pass
|
||||
|
||||
def remove(self, container):
|
||||
"""Remove an existing `container`
|
||||
"""
|
||||
pass
|
||||
29
pype/resolve/preload_console.py
Normal file
29
pype/resolve/preload_console.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env python
|
||||
import time
|
||||
from pype.resolve.utils import get_resolve_module
|
||||
from pypeapp import Logger
|
||||
|
||||
log = Logger().get_logger(__name__, "resolve")
|
||||
|
||||
wait_delay = 2.5
|
||||
wait = 0.00
|
||||
ready = None
|
||||
while True:
|
||||
try:
|
||||
# Create project and set parameters:
|
||||
resolve = get_resolve_module()
|
||||
pm = resolve.GetProjectManager()
|
||||
p = pm.GetCurrentProject()
|
||||
if p.GetName() == "Untitled Project":
|
||||
ready = None
|
||||
else:
|
||||
ready = True
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if ready is None:
|
||||
time.sleep(wait_delay)
|
||||
log.info(f"Waiting {wait}s for Resolve to be open in project")
|
||||
wait += wait_delay
|
||||
else:
|
||||
break
|
||||
34
pype/resolve/resolve_utility_scripts/Pype_menu.py
Normal file
34
pype/resolve/resolve_utility_scripts/Pype_menu.py
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
import os
|
||||
import sys
|
||||
import importlib
|
||||
import avalon
|
||||
import pype
|
||||
|
||||
from pypeapp import Logger
|
||||
|
||||
log = Logger().get_logger(__name__)
|
||||
|
||||
|
||||
def main(env):
|
||||
# Registers pype's Global pyblish plugins
|
||||
pype.install()
|
||||
|
||||
# Register Host (and it's pyblish plugins)
|
||||
host_name = env["AVALON_APP"]
|
||||
host_import_str = "pype.resolve"
|
||||
|
||||
try:
|
||||
host_module = importlib.import_module(host_import_str)
|
||||
except ModuleNotFoundError:
|
||||
log.error((
|
||||
f"Host \"{host_name}\" can't be imported."
|
||||
f" Import string \"{host_import_str}\" failed."
|
||||
))
|
||||
return False
|
||||
|
||||
avalon.api.install(host_module)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main(os.environ)
|
||||
sys.exit(not bool(result))
|
||||
1
pype/resolve/resolve_utility_scripts/README.markdown
Normal file
1
pype/resolve/resolve_utility_scripts/README.markdown
Normal file
|
|
@ -0,0 +1 @@
|
|||
|
||||
111
pype/resolve/resolve_utility_scripts/__test_gui.py
Normal file
111
pype/resolve/resolve_utility_scripts/__test_gui.py
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#! python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# DaVinci Resolve scripting proof of concept. Resolve page external switcher.
|
||||
# Local or TCP/IP control mode.
|
||||
# Refer to Resolve V15 public beta 2 scripting API documentation for host setup.
|
||||
# Copyright 2018 Igor Riđanović, www.hdhead.com
|
||||
from Qt.QtGui import *
|
||||
from Qt.QtWidgets import *
|
||||
from Qt.QtCore import *
|
||||
|
||||
import sys
|
||||
|
||||
# If API module not found assume we"re working as a remote control
|
||||
try:
|
||||
import DaVinciResolveScript
|
||||
# Instantiate Resolve object
|
||||
resolve = DaVinciResolveScript.scriptapp("Resolve")
|
||||
checkboxState = False
|
||||
except ImportError:
|
||||
print("Resolve API not found.")
|
||||
checkboxState = True
|
||||
|
||||
try:
|
||||
_encoding = QApplication.UnicodeUTF8
|
||||
|
||||
def _translate(context, text, disambig):
|
||||
return QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QApplication.translate(context, text, disambig)
|
||||
|
||||
|
||||
class Ui_Form(object):
|
||||
def setupUi(self, Form):
|
||||
Form.setObjectName(str("Resolve Page Switcher"))
|
||||
Form.resize(561, 88)
|
||||
Form.setStyleSheet(str((
|
||||
"background-color: #282828;"
|
||||
"border-color: #555555;"
|
||||
"color: #929292;"
|
||||
"font-size: 13px;"
|
||||
)))
|
||||
self.horizontalLayout = QHBoxLayout(Form)
|
||||
self.horizontalLayout.setObjectName(str("horizontalLayout"))
|
||||
self.mediaButton = QPushButton(Form)
|
||||
self.mediaButton.setObjectName(str("mediaButton"))
|
||||
self.horizontalLayout.addWidget(self.mediaButton)
|
||||
self.editButton = QPushButton(Form)
|
||||
self.editButton.setObjectName(str("editButton"))
|
||||
self.horizontalLayout.addWidget(self.editButton)
|
||||
self.fusionButton = QPushButton(Form)
|
||||
self.fusionButton.setObjectName(str("fusionButton"))
|
||||
self.horizontalLayout.addWidget(self.fusionButton)
|
||||
self.colorButton = QPushButton(Form)
|
||||
self.colorButton.setObjectName(str("colorButton"))
|
||||
self.horizontalLayout.addWidget(self.colorButton)
|
||||
self.fairlightButton = QPushButton(Form)
|
||||
self.fairlightButton.setObjectName(str("fairlightButton"))
|
||||
self.horizontalLayout.addWidget(self.fairlightButton)
|
||||
self.deliverButton = QPushButton(Form)
|
||||
self.deliverButton.setObjectName(str("deliverButton"))
|
||||
self.horizontalLayout.addWidget(self.deliverButton)
|
||||
|
||||
self.mediaButton.clicked.connect(lambda: self.pageswitch("media"))
|
||||
self.editButton.clicked.connect(lambda: self.pageswitch("edit"))
|
||||
self.fusionButton.clicked.connect(lambda: self.pageswitch("fusion"))
|
||||
self.colorButton.clicked.connect(lambda: self.pageswitch("color"))
|
||||
self.fairlightButton.clicked.connect(
|
||||
lambda: self.pageswitch("fairlight"))
|
||||
self.deliverButton.clicked.connect(lambda: self.pageswitch("deliver"))
|
||||
|
||||
self.mediaButton.setStyleSheet(str("background-color: #181818;"))
|
||||
self.editButton.setStyleSheet(str("background-color: #181818;"))
|
||||
self.fusionButton.setStyleSheet(
|
||||
str("background-color: #181818;"))
|
||||
self.colorButton.setStyleSheet(str("background-color: #181818;"))
|
||||
self.fairlightButton.setStyleSheet(
|
||||
str("background-color: #181818;"))
|
||||
self.deliverButton.setStyleSheet(
|
||||
str("background-color: #181818;"))
|
||||
|
||||
self.retranslateUi(Form)
|
||||
QMetaObject.connectSlotsByName(Form)
|
||||
|
||||
def retranslateUi(self, Form):
|
||||
Form.setWindowTitle(_translate("Resolve Page Switcher",
|
||||
"Resolve Page Switcher", None))
|
||||
self.mediaButton.setText(_translate("Form", "Media", None))
|
||||
self.editButton.setText(_translate("Form", "Edit", None))
|
||||
self.fusionButton.setText(_translate("Form", "Fusion", None))
|
||||
self.colorButton.setText(_translate("Form", "Color", None))
|
||||
self.fairlightButton.setText(_translate("Form", "Fairlight", None))
|
||||
self.deliverButton.setText(_translate("Form", "Deliver", None))
|
||||
|
||||
def pageswitch(self, page):
|
||||
# Send page name to server to switch remote Resolve"s page
|
||||
try:
|
||||
resolve.OpenPage(page)
|
||||
print(f"Switched to {page}")
|
||||
except NameError:
|
||||
print("Resolve API not found. Run in remote mode instead?")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = QApplication(sys.argv)
|
||||
Form = QWidget()
|
||||
ui = Ui_Form()
|
||||
ui.setupUi(Form)
|
||||
Form.show()
|
||||
sys.exit(app.exec_())
|
||||
57
pype/resolve/resolve_utility_scripts/__test_pyblish.py
Normal file
57
pype/resolve/resolve_utility_scripts/__test_pyblish.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import os
|
||||
import sys
|
||||
import pype
|
||||
import importlib
|
||||
import pyblish.api
|
||||
import pyblish.util
|
||||
import avalon.api
|
||||
from avalon.tools import publish
|
||||
from pypeapp import Logger
|
||||
|
||||
log = Logger().get_logger(__name__)
|
||||
|
||||
|
||||
def main(env):
|
||||
# Registers pype's Global pyblish plugins
|
||||
pype.install()
|
||||
|
||||
# Register Host (and it's pyblish plugins)
|
||||
host_name = env["AVALON_APP"]
|
||||
# TODO not sure if use "pype." or "avalon." for host import
|
||||
host_import_str = f"pype.{host_name}"
|
||||
|
||||
try:
|
||||
host_module = importlib.import_module(host_import_str)
|
||||
except ModuleNotFoundError:
|
||||
log.error((
|
||||
f"Host \"{host_name}\" can't be imported."
|
||||
f" Import string \"{host_import_str}\" failed."
|
||||
))
|
||||
return False
|
||||
|
||||
avalon.api.install(host_module)
|
||||
|
||||
# Register additional paths
|
||||
addition_paths_str = env.get("PUBLISH_PATHS") or ""
|
||||
addition_paths = addition_paths_str.split(os.pathsep)
|
||||
for path in addition_paths:
|
||||
path = os.path.normpath(path)
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
|
||||
pyblish.api.register_plugin_path(path)
|
||||
|
||||
# Register project specific plugins
|
||||
project_name = os.environ["AVALON_PROJECT"]
|
||||
project_plugins_paths = env.get("PYPE_PROJECT_PLUGINS") or ""
|
||||
for path in project_plugins_paths.split(os.pathsep):
|
||||
plugin_path = os.path.join(path, project_name, "plugins")
|
||||
if os.path.exists(plugin_path):
|
||||
pyblish.api.register_plugin_path(plugin_path)
|
||||
|
||||
return publish.show()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
result = main(os.environ)
|
||||
sys.exit(not bool(result))
|
||||
36
pype/resolve/resolve_utility_scripts/__test_subprocess.py
Normal file
36
pype/resolve/resolve_utility_scripts/__test_subprocess.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#! python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import sys
|
||||
from pypeapp import execute, Logger
|
||||
from pype.resolve.utils import get_resolve_module
|
||||
|
||||
log = Logger().get_logger("Resolve")
|
||||
|
||||
CURRENT_DIR = os.getenv("RESOLVE_UTILITY_SCRIPTS_DIR", "")
|
||||
python_dir = os.getenv("PYTHON36_RESOLVE")
|
||||
python_exe = os.path.normpath(
|
||||
os.path.join(python_dir, "python.exe")
|
||||
)
|
||||
|
||||
resolve = get_resolve_module()
|
||||
PM = resolve.GetProjectManager()
|
||||
P = PM.GetCurrentProject()
|
||||
|
||||
log.info(P.GetName())
|
||||
|
||||
|
||||
# ______________________________________________________
|
||||
# testing subprocessing Scripts
|
||||
testing_py = os.path.join(CURRENT_DIR, "ResolvePageSwitcher.py")
|
||||
testing_py = os.path.normpath(testing_py)
|
||||
log.info(f"Testing path to script: `{testing_py}`")
|
||||
|
||||
returncode = execute(
|
||||
[python_exe, os.path.normpath(testing_py)],
|
||||
env=dict(os.environ)
|
||||
)
|
||||
|
||||
# Check if output file exists
|
||||
if returncode != 0:
|
||||
log.error("Executing failed!")
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This file serves to return a DaVinci Resolve object
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
def GetResolve():
|
||||
try:
|
||||
# The PYTHONPATH needs to be set correctly for this import statement to work.
|
||||
# An alternative is to import the DaVinciResolveScript by specifying absolute path (see ExceptionHandler logic)
|
||||
import DaVinciResolveScript as bmd
|
||||
except ImportError:
|
||||
if sys.platform.startswith("darwin"):
|
||||
expectedPath="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting/Modules/"
|
||||
elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"):
|
||||
import os
|
||||
expectedPath=os.getenv('PROGRAMDATA') + "\\Blackmagic Design\\DaVinci Resolve\\Support\\Developer\\Scripting\\Modules\\"
|
||||
elif sys.platform.startswith("linux"):
|
||||
expectedPath="/opt/resolve/libs/Fusion/Modules/"
|
||||
|
||||
# check if the default path has it...
|
||||
print("Unable to find module DaVinciResolveScript from $PYTHONPATH - trying default locations")
|
||||
try:
|
||||
import imp
|
||||
bmd = imp.load_source('DaVinciResolveScript', expectedPath+"DaVinciResolveScript.py")
|
||||
except ImportError:
|
||||
# No fallbacks ... report error:
|
||||
print("Unable to find module DaVinciResolveScript - please ensure that the module DaVinciResolveScript is discoverable by python")
|
||||
print("For a default DaVinci Resolve installation, the module is expected to be located in: "+expectedPath)
|
||||
sys.exit()
|
||||
|
||||
return bmd.scriptapp("Resolve")
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
#! /usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This script tests Resolve 15 scripting API on MacOS.
|
||||
# We suspect an issue with import of fusionscript.so.
|
||||
# To test launch Resolve Studio first and then run this script.
|
||||
# The script will save a text report.
|
||||
# igor@hdhead.com
|
||||
|
||||
from datetime import datetime
|
||||
import os
|
||||
import sys
|
||||
import imp
|
||||
|
||||
eol = '\n'
|
||||
pathLib = 'C:\\Program Files\\Blackmagic Design\\DaVinci Resolve\\fusionscript.dll'
|
||||
|
||||
reportDir = "C:\\Users\\jezsc"
|
||||
|
||||
# Create initial report file. It will overwrite existing!
|
||||
reportName = 'Resolve_API_Report.txt'
|
||||
reportPath = os.path.join(reportDir, reportName)
|
||||
reportfile = open(reportPath, 'w')
|
||||
reportfile.close()
|
||||
|
||||
|
||||
def report(entry):
|
||||
# Print to console
|
||||
print entry
|
||||
|
||||
# Write a report entry
|
||||
reportfile = open(reportPath, 'a')
|
||||
reportfile.write(entry)
|
||||
reportfile.write(eol)
|
||||
reportfile.close()
|
||||
|
||||
|
||||
# These are the values we'll discover and save
|
||||
report('Time: ' + str(datetime.now()))
|
||||
report('Python Version: ' + sys.version)
|
||||
report('Interpreter Path: ' + sys.executable)
|
||||
report('___________________________________' + eol)
|
||||
|
||||
report('If no lines follow we have likely experienced a Fatal Python Error.')
|
||||
|
||||
try:
|
||||
# Will the API library import? Does it exist?
|
||||
smodule = imp.load_dynamic('fusionscript', pathLib)
|
||||
report('Imported fusionscript.so')
|
||||
|
||||
# It looks like the library imported. Can we create a resolve instance now?
|
||||
try:
|
||||
resolve = smodule.scriptapp('Resolve')
|
||||
if 'None' in str(type(resolve)):
|
||||
report('Resolve instance is created, but Resolve is not found.')
|
||||
sys.exit()
|
||||
if 'PyRemoteObject' in str(type(resolve)):
|
||||
report('Resolve instance is created and Resolve is responsive.')
|
||||
except Exception, e:
|
||||
report(str(e))
|
||||
|
||||
# Let's go nuts and count how many projects are in the Project Manager
|
||||
try:
|
||||
projman = resolve.GetProjectManager()
|
||||
projects = projman.GetProjectsInCurrentFolder()
|
||||
report('Project Count: ' + str(len(projects)))
|
||||
report('All is well!')
|
||||
except Exception, e:
|
||||
report(str(e))
|
||||
|
||||
except Exception, e:
|
||||
report(str(e))
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#!/usr/bin/env python3.6
|
||||
from python_get_resolve import GetResolve
|
||||
|
||||
resolve = GetResolve()
|
||||
PM = resolve.GetProjectManager()
|
||||
P = PM.GetCurrentProject()
|
||||
|
||||
print(P.GetName())
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
import time
|
||||
from python_get_resolve import GetResolve
|
||||
|
||||
wait_delay = 2.5
|
||||
wait = 0.00
|
||||
ready = None
|
||||
while True:
|
||||
try:
|
||||
# Create project and set parameters:
|
||||
resolve = GetResolve()
|
||||
PM = resolve.GetProjectManager()
|
||||
P = PM.GetCurrentProject()
|
||||
if P.GetName() == "Untitled Project":
|
||||
ready = None
|
||||
else:
|
||||
ready = True
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if ready is None:
|
||||
time.sleep(wait_delay)
|
||||
print(f"Waiting {wait}s for Resolve to be open inproject")
|
||||
wait += wait_delay
|
||||
else:
|
||||
break
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This file serves to return a DaVinci Resolve object
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
def GetResolve():
|
||||
try:
|
||||
# The PYTHONPATH needs to be set correctly for this import statement to work.
|
||||
# An alternative is to import the DaVinciResolveScript by specifying absolute path (see ExceptionHandler logic)
|
||||
import DaVinciResolveScript as bmd
|
||||
except ImportError:
|
||||
if sys.platform.startswith("darwin"):
|
||||
expectedPath="/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting/Modules/"
|
||||
elif sys.platform.startswith("win") or sys.platform.startswith("cygwin"):
|
||||
import os
|
||||
expectedPath=os.getenv('PROGRAMDATA') + "\\Blackmagic Design\\DaVinci Resolve\\Support\\Developer\\Scripting\\Modules\\"
|
||||
elif sys.platform.startswith("linux"):
|
||||
expectedPath="/opt/resolve/libs/Fusion/Modules/"
|
||||
|
||||
# check if the default path has it...
|
||||
print("Unable to find module DaVinciResolveScript from $PYTHONPATH - trying default locations")
|
||||
try:
|
||||
import imp
|
||||
bmd = imp.load_source('DaVinciResolveScript', expectedPath+"DaVinciResolveScript.py")
|
||||
except ImportError:
|
||||
# No fallbacks ... report error:
|
||||
print("Unable to find module DaVinciResolveScript - please ensure that the module DaVinciResolveScript is discoverable by python")
|
||||
print("For a default DaVinci Resolve installation, the module is expected to be located in: "+expectedPath)
|
||||
sys.exit()
|
||||
|
||||
return bmd.scriptapp("Resolve")
|
||||
114
pype/resolve/utils.py
Normal file
114
pype/resolve/utils.py
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#! python3
|
||||
|
||||
"""
|
||||
Resolve's tools for setting environment
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from pypeapp import Logger
|
||||
|
||||
log = Logger().get_logger(__name__, "resolve")
|
||||
|
||||
UTILITY_SCRIPTS = os.path.join(
|
||||
os.path.dirname(__file__),
|
||||
"resolve_utility_scripts"
|
||||
)
|
||||
|
||||
|
||||
def get_resolve_module():
|
||||
try:
|
||||
"""
|
||||
The PYTHONPATH needs to be set correctly for this import
|
||||
statement to work. An alternative is to import the
|
||||
DaVinciResolveScript by specifying absolute path
|
||||
(see ExceptionHandler logic)
|
||||
"""
|
||||
import DaVinciResolveScript as bmd
|
||||
except ImportError:
|
||||
if sys.platform.startswith("darwin"):
|
||||
expected_path = ("/Library/Application Support/Blackmagic Design"
|
||||
"/DaVinci Resolve/Developer/Scripting/Modules")
|
||||
elif sys.platform.startswith("win") \
|
||||
or sys.platform.startswith("cygwin"):
|
||||
expected_path = os.path.normpath(
|
||||
os.getenv('PROGRAMDATA') + (
|
||||
"/Blackmagic Design/DaVinci Resolve/Support/Developer"
|
||||
"/Scripting/Modules"
|
||||
)
|
||||
)
|
||||
elif sys.platform.startswith("linux"):
|
||||
expected_path = "/opt/resolve/libs/Fusion/Modules"
|
||||
|
||||
# check if the default path has it...
|
||||
print(("Unable to find module DaVinciResolveScript from "
|
||||
"$PYTHONPATH - trying default locations"))
|
||||
|
||||
module_path = os.path.normpath(
|
||||
os.path.join(
|
||||
expected_path,
|
||||
"DaVinciResolveScript.py"
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
import imp
|
||||
bmd = imp.load_source('DaVinciResolveScript', module_path)
|
||||
except ImportError:
|
||||
# No fallbacks ... report error:
|
||||
log.error(
|
||||
("Unable to find module DaVinciResolveScript - please "
|
||||
"ensure that the module DaVinciResolveScript is "
|
||||
"discoverable by python")
|
||||
)
|
||||
log.error(
|
||||
("For a default DaVinci Resolve installation, the "
|
||||
f"module is expected to be located in: {expected_path}")
|
||||
)
|
||||
sys.exit()
|
||||
|
||||
return bmd.scriptapp("Resolve")
|
||||
|
||||
|
||||
def _sync_utility_scripts(env=None):
|
||||
""" Synchronizing basic utlility scripts for resolve.
|
||||
|
||||
To be able to run scripts from inside `Resolve/Workspace/Scripts` menu
|
||||
all scripts has to be accessible from defined folder.
|
||||
"""
|
||||
if not env:
|
||||
env = os.environ
|
||||
|
||||
us_dir = env.get("RESOLVE_UTILITY_SCRIPTS_DIR", "")
|
||||
scripts = os.listdir(UTILITY_SCRIPTS)
|
||||
|
||||
log.info(f"Utility Scripts Dir: `{UTILITY_SCRIPTS}`")
|
||||
log.info(f"Utility Scripts: `{scripts}`")
|
||||
|
||||
# make sure no script file is in folder
|
||||
if next((s for s in os.listdir(us_dir)), None):
|
||||
for s in os.listdir(us_dir):
|
||||
path = os.path.join(us_dir, s)
|
||||
log.info(f"Removing `{path}`...")
|
||||
os.remove(path)
|
||||
|
||||
# copy scripts into Resolve's utility scripts dir
|
||||
for s in scripts:
|
||||
src = os.path.join(UTILITY_SCRIPTS, s)
|
||||
dst = os.path.join(us_dir, s)
|
||||
log.info(f"Copying `{src}` to `{dst}`...")
|
||||
shutil.copy2(src, dst)
|
||||
|
||||
|
||||
def setup(env=None):
|
||||
""" Wrapper installer started from pype.hooks.resolve.ResolvePrelaunch()
|
||||
"""
|
||||
if not env:
|
||||
env = os.environ
|
||||
|
||||
# synchronize resolve utility scripts
|
||||
_sync_utility_scripts(env)
|
||||
|
||||
log.info("Resolve Pype wrapper has been installed")
|
||||
88
pype/resolve/workio.py
Normal file
88
pype/resolve/workio.py
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
"""Host API required Work Files tool"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pypeapp import Logger
|
||||
from .utils import get_resolve_module
|
||||
|
||||
log = Logger().get_logger(__name__, "nukestudio")
|
||||
|
||||
exported_projet_ext = ".drp"
|
||||
|
||||
self = sys.modules[__name__]
|
||||
self.pm = None
|
||||
|
||||
|
||||
def get_project_manager():
|
||||
if not self.pm:
|
||||
resolve = get_resolve_module()
|
||||
self.pm = resolve.GetProjectManager()
|
||||
return self.pm
|
||||
|
||||
|
||||
def file_extensions():
|
||||
return [exported_projet_ext]
|
||||
|
||||
|
||||
def has_unsaved_changes():
|
||||
get_project_manager().SaveProject()
|
||||
return False
|
||||
|
||||
|
||||
def save_file(filepath):
|
||||
pm = get_project_manager()
|
||||
file = os.path.basename(filepath)
|
||||
fname, _ = os.path.splitext(file)
|
||||
project = pm.GetCurrentProject()
|
||||
name = project.GetName()
|
||||
|
||||
if "Untitled Project" not in name:
|
||||
log.info("Saving project: `{}` as '{}'".format(name, file))
|
||||
pm.ExportProject(name, filepath)
|
||||
else:
|
||||
log.info("Creating new project...")
|
||||
pm.CreateProject(fname)
|
||||
pm.ExportProject(name, filepath)
|
||||
|
||||
|
||||
def open_file(filepath):
|
||||
"""
|
||||
Loading project
|
||||
"""
|
||||
pm = get_project_manager()
|
||||
file = os.path.basename(filepath)
|
||||
fname, _ = os.path.splitext(file)
|
||||
|
||||
# deal with current project
|
||||
project = pm.GetCurrentProject()
|
||||
pm.SaveProject()
|
||||
pm.CloseProject(project)
|
||||
|
||||
try:
|
||||
# load project from input path
|
||||
project = pm.LoadProject(fname)
|
||||
log.info(f"Project {project.GetName()} opened...")
|
||||
return True
|
||||
except NameError as E:
|
||||
log.error(f"Project with name `{fname}` does not exist!\n\nError: {E}")
|
||||
return False
|
||||
|
||||
|
||||
def current_file():
|
||||
pm = get_project_manager()
|
||||
current_dir = os.getenv("AVALON_WORKDIR")
|
||||
project = pm.GetCurrentProject()
|
||||
name = project.GetName()
|
||||
fname = name + exported_projet_ext
|
||||
current_file = os.path.join(current_dir, fname)
|
||||
normalised = os.path.normpath(current_file)
|
||||
|
||||
# Unsaved current file
|
||||
if normalised == "":
|
||||
return None
|
||||
|
||||
return normalised
|
||||
|
||||
|
||||
def work_root(session):
|
||||
return os.path.normpath(session["AVALON_WORKDIR"]).replace("\\", "/")
|
||||
Loading…
Add table
Add a link
Reference in a new issue