Tweak software, Shotgun software and Autodesk. Lot of things have happened, but RV is still one of my favourite softwares, and it have been for the past 10+ years. When it comes to customization you have a lot of possibilities with Python and RV's Mu language. The Mu API documentation is only available inside RV and unfortionatly we don't have a Python API documentation (yet)... but it is pretty similar to Mu's :) Below are some notes by our pipeline TD; Emil Gunnarsson that hopefully can be usefull and save some time for someone. At the bottom he lists some useful links.
Environment Variables:
At Dupp we use RV_PREFS_CLOBBER_PATH and RV_SUPPORT_PATH and they are pointing to the same network directory.
rv
in python you should set the PYTONPATH=C:\Program Files\Shotgun\RV-2021.0.0\plugins\Python
environment variable on your machine.from rv.rvtypes import *
# These two are only available in the RV Runtime Environment
from rv.commands import *
from rv.extra_commands import *
class DuppMenuMode(MinorMode):
def __init__(self):
MinorMode.__init__(self)
# Edit the existing list menu, and add a new dropdown to it, with 2 items
self.init(
"py-duppmenu-mode",
None,
None,
[
# Menu name
# NOTE: If it already exists it will merge with existing, and add submenus / menuitems to the existing one
("-= DUPP =-",
[
# Menuitem name, actionHook (event), key, stateHook
("Print to console", self.printToConsole, None, None),
("Show console", self.showConsole, None, None)
]
)
]
)
# Open the console if it is not already open
if not isConsoleVisible():
showConsole()
def printToConsole(self, event):
print("Printing information to the console: ")
print(getCurrentAttributes())
def showConsole(self, event):
print("Showing console!")
if not isConsoleVisible():
showConsole()
def createMode():
# This function will automatically be called by RV
# to initialize the Class
return DuppMenuMode()
package: DuppMenu
author: Emil Gunnarsson
contact: This email address is being protected from spambots. You need JavaScript enabled to view it.
version: 1.0
rv: 3.6
requires: ''
modes:
- file: myMenu
load: immediate
description: A DuppMenu that allows you to communincate with the Ingrid Python API
-1.0
and the extension .rvpkg
in order for it to show up when you want to add it to RV.
def getColorSpace(self):
colorspace = "linear"
# Return Nuke-style colorspaces
# Property types: 1 = float, 2 = int, 8 = string
# int, int, int, float
# Gives a list of 1 element so we use [0] to get the first one (the value)
# We are getting the values for logtype, sRGB2Linear, Rec709ToLinear & Gamma
nLogtype = commands.getIntProperty("sourceGroup000000_tolinPipeline_0.color.logtype")[0]
nRGB2Lin = commands.getIntProperty("sourceGroup000000_tolinPipeline_0.color.sRGB2linear")[0]
nRec2Lin = commands.getIntProperty("sourceGroup000000_tolinPipeline_0.color.Rec709ToLinear")[0]
fGamma22 = round(commands.getFloatProperty("sourceGroup000000_tolinPipeline_0.color.fileGamma")[0], 1)
if fGamma22 == 2.2:
colorspace = "Gamma2.2"
elif nLogtype == 1:
colorspace = "Cineon"
elif nLogtype == 2:
colorspace = "ViperLog"
elif nLogtype == 3 or nLogtype == 4:
colorspace = "AlexaV3LogC"
elif nLogtype == 6 or nLogtype == 7:
colorspace = "REDLog"
elif nLogtype == 0 and nRGB2Lin == 1:
colorspace = "sRGB"
elif nLogtype == 0 and nRec2Lin == 1:
colorspace = "rec709"
return colorspace
def displayMessageBox(self, title, message, messageType = QMessageBox.Ok):
# Create a simple message dialog
msg = QMessageBox()
msg.setIcon(QMessageBox.Information)
msg.setText(message)
msg.setWindowTitle(title)
msg.setStandardButtons(messageType)
msg.exec_()
# # Additional useful methods
# msg.setInformativeText("This is additional information")
# msg.setDetailedText("The details are as follows:")
# msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
# QMessageBox.Ok 0x00000400
# QMessageBox.Open 0x00002000
# QMessageBox.Save 0x00000800
# QMessageBox.Cancel 0x00400000
# QMessageBox.Close 0x00200000
# QMessageBox.Yes 0x00004000
# QMessageBox.No 0x00010000
# QMessageBox.Abort 0x00040000
# QMessageBox.Retry 0x00080000
# QMessageBox.Ignore 0x00100000
# # The method should take an index for the buttons
# # EXAMPLE: def buttonClicked(self, index):
# msg.buttonClicked.connect(self.buttonClicked)
# # Get return value from the button clicked
# retval = msg.exec_()
# print("value of pressed message box button: ", retval)
# new-source, graph-state-change, after-progressive-loading, media-relocated
commands.bind("default", "global", "media-relocated", self.mediaRelocated, "Doc string")
commands.bind("default", "global", "graph-state-change", self.testEvent, "Doc string")
# Events
def mediaRelocated(self, event):
self.hasBeenRelocated = True
print("Media relocated...")
def testEvent(self, event):
print("another event")
nodeTypes = ['RVSequence', 'RVStack', 'RVSwitch']
for nodeType in nodeTypes:
print("INFO: Checking nodes of type \""+nodeType+"\"")
nodes = rv.commands.nodesOfType(nodeType)
counter = 0
for node in nodes:
props = commands.properties(node)
length = len(nodes)
for prop in props:
propertyType = commands.propertyInfo(prop)['type']
# I know there is some type called "halfproperty" but i havent come across it yet
if propertyType == 1:
print("Float property value ("+ prop +"): ", commands.getFloatProperty(prop))
elif propertyType == 2:
print("Integer property value: ("+ prop +")", commands.getIntProperty(prop))
elif propertyType == 8:
print("String property value: ("+ prop +")", commands.getStringProperty(prop))
else:
print("PROPERTY TYPE: ", propertyType)
if length > 1 and counter != (length - 1):
print("------------------------------------------------------------------------------------------")
counter += 1
print("=============================================")
import sys
sys.path.append("L:\\_DUPP_PIPE\\app_launcher\\DuppAppLauncher\\Code")
from rv.qtutils import *
from rv.rvtypes import *
import duppmenu
# These two are only available during the RV Runtime Environment
from rv.commands import *
from rv.extra_commands import *
from PySide.QtGui import *
from PySide.QtCore import *
from PySide.QtUiTools import QUiLoader
from Ingrid import IngridAPI
class DuppMenuMode(MinorMode):
def __init__(self):
MinorMode.__init__(self)
self.init("py-duppmenu-mode", None, None, [("-= DUPP =-",[("Publish", self.publish, None, None)])])
# Variables
self.comboBoxLayoutCounter = 0
self.currentFolderIds = {'f_id': None, 'f_parent_id': None}
self.isSpecialCase = False
# Ingrid
self.ingrid = IngridAPI()
# GUI
# Load custom Widget to place on top of the Docked Widget
# This is simply a new .ui file which was created as a "Widget" (Not a MainWindow), then simply add a Frame to it and layout it
# Add your desired widgets and find them using .findChild(QObject, "identifier")
loader = QUiLoader()
ui_file = QFile(os.path.join(self.supportPath(duppmenu, "duppmenu"), "CustomDockWidget.ui"))
ui_file.open(QFile.ReadOnly)
self.customDockWidget = loader.load(ui_file)
ui_file.close()
# Target custom widgets
self.comboBox_0 = self.customDockWidget.findChild(QComboBox, "comboBox_0")
self.comboBoxLayout = self.customDockWidget.findChild(QVBoxLayout, "comboBoxLayout")
# Event handlers
self.comboBox_0.currentIndexChanged.connect(lambda: self.onComboBoxIndexChanged(self.comboBox_0))
# Gets the current RV session windows as a PySide QMainWindow.
self.rvWindow = rv.qtutils.sessionWindow()
# Create DockWidget and add the Custom Widget to it
self.dockWidget = QDockWidget("Publish", self.rvWindow)
self.dockWidget.setWidget(self.customDockWidget)
# Dock widget to the RV MainWindow
self.rvWindow.addDockWidget(Qt.RightDockWidgetArea, self.dockWidget)
https://support.shotgunsoftware.com/hc/en-us/articles/219042308-RV-Python-quickstart
https://community.shotgunsoftware.com/t/what-are-some-useful-python-snippets-for-working-in-rv/102
https://support.shotgunsoftware.com/hc/en-us/community/posts/209495248-Replacing-Images
Let me know your thoughts or reach out if you have any questions.
Best,
Anders
This email address is being protected from spambots. You need JavaScript enabled to view it.
COME AND VISIT OUR STUDIO IN
HANGAR 80 – KARLSBORG, SWEDEN.
Flygfältsvägen 29
546 30 Karlsborg
Västra Götaland
Dubbeltupp AB
Lerbro 2
SE-546 92 Mölltorp
Anders Nyman
+46 (0)70-79 44 265
This email address is being protected from spambots. You need JavaScript enabled to view it.
Christian Olander
+46 (0)70-53 85 120
This email address is being protected from spambots. You need JavaScript enabled to view it.
Per Nyman
+46 (0)73-98 44 595
This email address is being protected from spambots. You need JavaScript enabled to view it.
Håkan Ossiann
+46 (0)70-47 45 177
This email address is being protected from spambots. You need JavaScript enabled to view it.