Skip to content

Commit 7567164

Browse files
fix: QOL support for PySide6, basic standalone mode
This commits adds: - Qt.py as an abstraction for PySide2/6, in order to support Maya 2025. - Replaced QRegExp with python's built-in re module. - Standalone mode by executing ReferenceImporterMain.py with python. - Relative imports.
1 parent 9d665eb commit 7567164

File tree

10 files changed

+2214
-57
lines changed

10 files changed

+2214
-57
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ __pycache__/
99
# Distribution / packaging
1010
.Python
1111
build/
12+
bin/
1213
develop-eggs/
1314
dist/
1415
downloads/
@@ -148,4 +149,4 @@ cython_debug/
148149
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
149150
# and can be added to the global gitignore or merged into this file. For a more nuclear
150151
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
151-
#.idea/
152+
#.idea/

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Script that automates the importing of video reference into Maya, automatically
99
## 2. Copy the contents of the zip to you Maya scripts folder
1010
>found under 'Documents/maya/***InsertMayaVerion***/scripts'
1111
## 2. Run the following command in Maya
12-
from ReferenceImporterMain import ReferenceImporterDialog
13-
ReferenceImporterDialog.run()
12+
import reference_importer
13+
reference_importer.run()
1414
make sure to run it using Python
1515

1616
# Usage
@@ -24,4 +24,4 @@ make sure to run it using Python
2424
### 3. Set output sequence name and format
2525
### 4. Set output directory for the sequence
2626
### 5. (Optional) auto creation of image plane in Maya for the sequence
27-
### 6. Import the video!!
27+
### 6. Import the video!!

ReferenceImporterMain.py

Lines changed: 51 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -2,48 +2,72 @@
22
# Reference Importer v1.1, made by Jaime Florian
33
# Video Demonstration: https://www.youtube.com/watch?v=ObX9NU2BmZo
44

5-
import os
65
import sys
7-
libs = os.path.abspath(os.path.dirname(__file__))
8-
libs = os.path.join(libs,'lib')
9-
sys.path.append(libs)
10-
from PySide2 import QtCore,QtGui,QtWidgets
11-
import maya.cmds as cmds
12-
import maya.OpenMaya as om
13-
import maya.OpenMayaUI as omui
14-
from shiboken2 import wrapInstance
15-
from reference_importer import ImageSequencer, Ui
6+
from pathlib import Path
7+
8+
VENDOR_PATH = Path(__file__).parent.resolve() / "vendor"
9+
sys.path.insert(0, str(VENDOR_PATH))
10+
11+
import os
12+
import re
13+
from Qt import QtCore,QtWidgets
14+
from Qt.QtCompat import wrapInstance
15+
16+
try:
17+
import maya.cmds as cmds
18+
import maya.OpenMaya as om
19+
import maya.OpenMayaUI as omui
20+
IN_MAYA = True
21+
except ImportError:
22+
IN_MAYA = False
23+
24+
from .reference_importer import ImageSequencer, Ui
1625

1726

1827

1928
def maya_main_window():
2029
"""
2130
Return the Maya main window widget as a Python object
2231
"""
32+
if not IN_MAYA:
33+
return None
34+
2335
main_window_ptr = omui.MQtUtil.mainWindow()
2436
return wrapInstance(int(main_window_ptr), QtWidgets.QWidget)
2537
class ReferenceImporterDialog(QtWidgets.QDialog):
2638

2739
dlg_instance = None
40+
qapp_instance = None
2841

2942
@classmethod
3043
def run(cls):
31-
if not cls.dlg_instance:
32-
cls.dlg_instance = ReferenceImporterDialog()
44+
if IN_MAYA:
45+
if not cls.dlg_instance:
46+
cls.dlg_instance = ReferenceImporterDialog()
3347

34-
if cls.dlg_instance.isHidden():
35-
cls.dlg_instance.show()
36-
else:
37-
cls.dlg_instance.raise_()
38-
cls.dlg_instance.activateWindow()
48+
if cls.dlg_instance.isHidden():
49+
cls.dlg_instance.show()
50+
else:
51+
cls.dlg_instance.raise_()
52+
cls.dlg_instance.activateWindow()
53+
return
54+
55+
if not cls.qapp_instance:
56+
cls.qapp_instance = QtWidgets.QApplication(sys.argv)
57+
58+
dialog = ReferenceImporterDialog()
59+
dialog.show()
60+
cls.qapp_instance.exec_()
3961

40-
def __init__(self,parent=maya_main_window()):
62+
def __init__(self, parent=maya_main_window()):
4163
super(ReferenceImporterDialog,self).__init__(parent)
4264
self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
4365
self.imageSequencer = ImageSequencer()
4466
self.ui = Ui(self)
4567
self.CreateConnections()
4668
self.ui.pushButton_create_image_sequence.setDisabled(True)
69+
if not IN_MAYA:
70+
self.ui.checkBox_imagePlane.setDisabled(True)
4771

4872
def CreateConnections(self):
4973
self.ui.pushButton_fileExplorer_input.clicked.connect(self.SetInput)
@@ -107,14 +131,13 @@ def CheckText(self):
107131
except Exception as e:
108132
raise e
109133

110-
def ValidateTimecode(self, text, ):
111-
timecode_rx = QtCore.QRegExp('([0-9]{2}[:]){1,2}[0-9]{2}[.]?[0-9]{0,2}')
112-
timecode_validator = QtGui.QRegExpValidator(timecode_rx, self)
113-
state = timecode_validator.validate(text,0)
114-
if state[0] == QtGui.QRegExpValidator.Acceptable :
115-
return True
116134

117-
else :
135+
def ValidateTimecode(self, text):
136+
timecode_rx = r'([0-9]{2}[:]){1,2}[0-9]{2}[.]?[0-9]{0,2}'
137+
state = re.fullmatch(timecode_rx, text)
138+
if state:
139+
return True
140+
else:
118141
return False
119142

120143
def CreateImageSequence(self):
@@ -136,12 +159,12 @@ def CreateImageSequence(self):
136159
trim_start,trim_end,
137160
output_file)
138161

139-
if self.ui.checkBox_imagePlane.isChecked():
162+
if self.ui.checkBox_imagePlane.isChecked() and IN_MAYA:
140163
output_file = output_file.replace('%03d', '001')
141164
image_plane = cmds.imagePlane(fn = output_file)
142165
cmds.setAttr("%s.useFrameExtension"%image_plane[0],True)
143166
except Exception as e:
144167
raise e
145168

146-
if 'name' == "__main__":
147-
pass
169+
if __name__ == "__main__":
170+
ReferenceImporterDialog.run()

__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
from ReferenceImporterMain import ReferenceImporterDialog
1+
from .ReferenceImporterMain import ReferenceImporterDialog
22

33
def run():
44
ReferenceImporterDialog.run()
55

66

77
if __name__ == "__main__":
8-
run()
8+
run()

lib/ffmpeg/ffmpeg.exe

-91.4 MB
Binary file not shown.

reference_importer/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
from imageSequence import ImageSequencer
2-
from ui import Ui
1+
from .imageSequence import ImageSequencer
2+
from .ui import Ui
Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# -*- coding: utf-8 -*-
2-
import sys
3-
import os
2+
from pathlib import Path
43
import subprocess
54

65

@@ -18,32 +17,25 @@ def __init__(self, video_file="",
1817
self.padding = padding
1918
self.trim_start = 0
2019
self.trim_end = 0
21-
self.encoding = 'cp1252'
22-
self.ffmpeg_path = os.path.abspath(os.path.dirname(__file__)
23-
).decode(self.encoding)
24-
self.ffmpeg_path = os.path.join(self.ffmpeg_path,
25-
'..',
26-
'lib',
27-
'ffmpeg',
28-
'ffmpeg')
20+
self.ffmpeg_path = Path(__file__).parent.parent.resolve() / "bin" / "ffmpeg"
2921

3022
def getDuration(self, video_file):
31-
command = (u'"%s" -i "%s" 2>&1 | findstr "Duration"' %(self.ffmpeg_path,video_file)).encode(self.encoding)
23+
command = (u'"%s" -i "%s" 2>&1 | findstr "Duration"' %(self.ffmpeg_path,video_file))
3224
try:
33-
process = subprocess.check_output(command, shell=True).encode(self.encoding)
25+
process = subprocess.check_output(command, shell=True)
3426
process = str(process).strip()
3527
process = process.split(" ")
36-
process = process[1][0:11]
28+
process = process[3][0:11]
3729
except Exception as e:
3830
raise e
3931
return process
4032
def createSequence(self,input_file, frameRate,start_trim,end_trim, output_file):
41-
command = ('"%s" -i "%s" -r %s -vf scale=1280:-1 -q:v 3 -ss %s -to %s "%s"' % (self.ffmpeg_path,input_file,frameRate,start_trim,end_trim,output_file)).encode(self.encoding)
33+
command = ('"%s" -i "%s" -r %s -vf scale=1280:-1 -q:v 3 -ss %s -to %s "%s"' % (self.ffmpeg_path,input_file,frameRate,start_trim,end_trim,output_file))
4234
try:
43-
subprocess.call(command)
35+
subprocess.run(command, shell=True)
4436
except Exception as e:
4537
raise e
4638

4739

4840
if __name__ == "__main__":
49-
pass
41+
pass

reference_importer/ui/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
from main_dialog_ui import Ui
1+
from .main_dialog_ui import Ui

reference_importer/ui/main_dialog_ui.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
## WARNING! All changes made in this file will be lost when recompiling UI file!
99
################################################################################
1010

11-
from PySide2.QtCore import *
12-
from PySide2.QtGui import *
13-
from PySide2.QtWidgets import *
11+
# Use Qt.py to support multiple Qt versions.
12+
# Should already be in sys.path when running through ReferenceImporterMain.py.
13+
14+
from Qt.QtCore import *
15+
from Qt.QtGui import *
16+
from Qt.QtWidgets import *
1417

1518

1619
class Ui(object):
@@ -145,7 +148,7 @@ def __init__(self, Dialog):
145148
# setupUi
146149

147150
def setTexts(self, Dialog):
148-
Dialog.setWindowTitle(u"Reference Importer v1.1")
151+
Dialog.setWindowTitle(u"Reference Importer v1.1.2")
149152
self.groupBox_input.setTitle(u"Input")
150153
self.label_video_file.setText(u"Video File")
151154
self.pushButton_fileExplorer_input.setText(u"Open...")

0 commit comments

Comments
 (0)