├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── _project ├── 0_pipeline │ ├── .gitkeep │ └── meta │ │ ├── assetName_GEO_v002.jpg │ │ └── s010_ANIM_v000.jpg ├── 1_sandbox │ ├── .gitkeep │ └── arichter │ │ └── .gitkeep ├── 2_preproduction │ ├── .gitkeep │ ├── _references │ │ └── .gitkeep │ ├── animatic │ │ └── .gitkeep │ ├── concept_art │ │ └── .gitkeep │ ├── making_of │ │ └── .gitkeep │ ├── presentation │ │ └── .gitkeep │ ├── promotion │ │ └── .gitkeep │ ├── protocol │ │ └── .gitkeep │ ├── rnd │ │ └── .gitkeep │ ├── screenplay │ │ └── .gitkeep │ └── storyboard │ │ └── .gitkeep ├── 3_footage │ ├── .gitkeep │ ├── hdri │ │ └── .gitkeep │ ├── scene │ │ └── .gitkeep │ ├── shader │ │ └── .gitkeep │ └── texture │ │ └── .gitkeep ├── 4_assets │ ├── .gitkeep │ └── assetName │ │ ├── .gitkeep │ │ ├── GEO │ │ ├── .gitkeep │ │ ├── PUBLISH │ │ │ └── assetName_GEO_v002.ma │ │ └── WORK │ │ │ ├── assetName_GEO_v001.ma │ │ │ └── assetName_GEO_v002.ma │ │ ├── RIG │ │ ├── .gitkeep │ │ └── PUBLISH │ │ │ └── .gitkeep │ │ └── SHD │ │ ├── .gitkeep │ │ └── PUBLISH │ │ └── .gitkeep ├── 4_shots │ ├── .gitkeep │ └── s010 │ │ └── ANIM │ │ └── WORK │ │ └── s010_ANIM_v000.ma ├── 5_post │ ├── .keep │ ├── deliver │ │ └── .keep │ ├── edit │ │ ├── .keep │ │ ├── cut │ │ │ └── .keep │ │ ├── music │ │ │ └── .keep │ │ └── sound │ │ │ └── .keep │ ├── grade │ │ └── .keep │ └── mov │ │ └── .keep └── README.txt ├── apps ├── __init__.py ├── arConfig.py ├── arConfig.ui ├── arDesktop.py ├── arLoad.py ├── arLoad.ui ├── arNotice.py ├── arNotice.ui ├── arSave.py ├── arSave.ui ├── arSplash.py ├── arSplash.ui ├── arUtil.py └── arUtil.ui ├── config ├── plex.yml ├── projects │ ├── .keep │ └── default │ │ ├── meta.yml │ │ ├── project.yml │ │ ├── script.yml │ │ └── software │ │ ├── houdini.yml │ │ ├── max.yml │ │ ├── maya.yml │ │ └── nuke.yml └── users │ ├── .keep │ └── arichter │ └── user.yml ├── exe ├── .keep ├── linux │ ├── Desktop.sh │ ├── Maya.sh │ └── setup_env.sh └── windows │ ├── 3dsMax.bat │ ├── desktop.bat │ ├── houdini.bat │ ├── maya.bat │ ├── nuke.bat │ └── python_check.bat ├── img ├── __init__.py ├── icons │ ├── app_modify.png │ ├── arrow_down.png │ ├── calendar.png │ ├── camera.png │ ├── cancel.png │ ├── cancel2.png │ ├── check.png │ ├── check_inbox.png │ ├── check_tasks.png │ ├── checks.png │ ├── code.png │ ├── customize.png │ ├── default.png │ ├── download.png │ ├── download1.png │ ├── email.png │ ├── email_yellow.png │ ├── file_add.png │ ├── file_code.png │ ├── file_delete.png │ ├── file_image.png │ ├── file_load.png │ ├── file_modify.png │ ├── file_move.png │ ├── file_open.png │ ├── file_play.png │ ├── folder_closed.png │ ├── folder_content.png │ ├── folder_open.png │ ├── help.png │ ├── help2.png │ ├── load.png │ ├── load2.png │ ├── load_yellow.png │ ├── minus1.png │ ├── minus2.png │ ├── minus3.png │ ├── minus4.png │ ├── notification.png │ ├── notification_new.png │ ├── p.png │ ├── p_yellow.png │ ├── pen.png │ ├── pipeline.png │ ├── plus1.png │ ├── plus2.png │ ├── plus3.png │ ├── plus4.png │ ├── project.png │ ├── project2.png │ ├── save.png │ ├── save2.png │ ├── settings.png │ ├── software.png │ ├── update.png │ ├── update_screen.png │ ├── upload_cloud.png │ └── user_modify.png ├── labels │ ├── default.png │ ├── shader.png │ └── shot.png ├── menu │ ├── separator.png │ ├── shelf_atools.png │ ├── shelf_attach_shader.png │ ├── shelf_camera.png │ ├── shelf_creation.png │ ├── shelf_default.png │ ├── shelf_graph_editor.png │ ├── shelf_help.png │ ├── shelf_hypershade.png │ ├── shelf_light.png │ ├── shelf_light_linker.png │ ├── shelf_load.png │ ├── shelf_name.png │ ├── shelf_node_editor.png │ ├── shelf_open_folder.png │ ├── shelf_open_folder_project.png │ ├── shelf_outliner.png │ ├── shelf_play.png │ ├── shelf_playblast.png │ ├── shelf_publish.png │ ├── shelf_refresh_pipe.png │ ├── shelf_rename.png │ ├── shelf_render.png │ ├── shelf_render_deliver.png │ ├── shelf_render_preview.png │ ├── shelf_render_work.png │ ├── shelf_renderthreads.png │ ├── shelf_report.png │ ├── shelf_save.png │ ├── shelf_snap.png │ ├── shelf_switch_abc.png │ ├── shelf_switch_ass.png │ ├── shelf_switch_box.png │ ├── shelf_switch_gpu.png │ ├── shelf_switch_loc.png │ ├── shelf_switch_ma.png │ └── shelf_viewport.png ├── software │ ├── default │ │ ├── 3dCoat.png │ │ ├── CPlusPlus.png │ │ ├── afterEffects.png │ │ ├── alembic.png │ │ ├── arnold.png │ │ ├── blender.png │ │ ├── bridge.png │ │ ├── cinema4d.png │ │ ├── csharp.png │ │ ├── davinci.png │ │ ├── default.png │ │ ├── folder.png │ │ ├── houdini.png │ │ ├── img.png │ │ ├── katana.png │ │ ├── mari.png │ │ ├── max.png │ │ ├── maxScript.png │ │ ├── maya.png │ │ ├── mel.png │ │ ├── mentalray.png │ │ ├── modo.png │ │ ├── motionbuilder.png │ │ ├── motive.png │ │ ├── nuke.png │ │ ├── pdf.png │ │ ├── pftrack.png │ │ ├── photoscan.png │ │ ├── photoshop.png │ │ ├── premiere.png │ │ ├── ptex.png │ │ ├── python.png │ │ ├── pythonBG.png │ │ ├── qt.png │ │ ├── quicktimeplayer.png │ │ ├── redshift.png │ │ ├── renderman.png │ │ ├── rv.png │ │ ├── unity.png │ │ ├── vlc.png │ │ ├── vray.png │ │ ├── yeti.png │ │ └── zbrush.png │ ├── houdini │ │ ├── houdini.ico │ │ ├── houdini.png │ │ └── houdini_splash.png │ ├── max │ │ ├── max.ico │ │ ├── max.png │ │ └── splash.bmp │ ├── maya │ │ ├── MayaEDUStartupImage.png │ │ ├── MayaStartupImage.png │ │ ├── maya.ico │ │ └── maya.png │ └── nuke │ │ ├── menu │ │ ├── help.ico │ │ ├── load.ico │ │ ├── nuke_toolbar.png │ │ ├── report.ico │ │ ├── save.ico │ │ ├── write.ico │ │ └── writeBanner52.png │ │ ├── nuke.ico │ │ └── nuke.png └── user │ ├── alexa.png │ ├── arichter.png │ └── default.png ├── scripts ├── __init__.py ├── extern │ ├── Qt.py │ ├── __init__.py │ └── yaml │ │ ├── __init__.py │ │ ├── composer.py │ │ ├── constructor.py │ │ ├── cyaml.py │ │ ├── dumper.py │ │ ├── emitter.py │ │ ├── error.py │ │ ├── events.py │ │ ├── loader.py │ │ ├── nodes.py │ │ ├── parser.py │ │ ├── reader.py │ │ ├── representer.py │ │ ├── resolver.py │ │ ├── scanner.py │ │ ├── serializer.py │ │ └── tokens.py ├── plex.py ├── plexfunc.py ├── plexlog.py ├── plexstart.py ├── snapshot.py └── software.py └── software ├── houdini ├── __init__.py ├── init │ ├── MainMenuMaster.xml │ ├── __init__.py │ └── init.py ├── plugins │ └── __init__.py └── scripts │ ├── __init__.py │ └── houdini_dcc.py ├── max ├── __init__.py ├── init │ ├── __init__.py │ ├── startup.ms │ └── startup.py ├── plugins │ └── __init__.py └── scripts │ ├── __init__.py │ └── max_dcc.py ├── maya ├── __init__.py ├── init │ ├── __init__.py │ └── userSetup.py ├── maya_dcc.py ├── plugins │ └── __init__.py └── scripts │ ├── ANIM │ ├── __init__.py │ └── playblast.py │ ├── LGT │ ├── __init__.py │ └── light_linker.py │ ├── SHD │ ├── __init__.py │ ├── create_shader.py │ └── unite_shader_group.py │ ├── __init__.py │ └── maya_utils.py └── nuke ├── __init__.py ├── gizmos ├── __init__.py ├── arAlphaPlate.gizmo ├── arLetterbox.gizmo └── arWrite.gizmo ├── init ├── __init__.py ├── init.py └── menu.py ├── plugins └── __init__.py └── scripts ├── __init__.py ├── nuke_dcc.py └── write_node.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # THIS IS ONLY FOR THE gitattributes REPOSITORY. 2 | # Handle line endings automatically for files detected as text 3 | # and leave all files detected as binary untouched. 4 | * text=auto 5 | 6 | # 7 | # The above will handle all files NOT found below 8 | # 9 | # These files are text and should be normalized (Convert crlf => lf) 10 | *.gitattributes text 11 | .gitignore text 12 | *.md text 13 | 14 | 15 | 16 | # PYTHON 17 | # Basic .gitattributes for a python repo. 18 | 19 | # Source files 20 | # ============ 21 | *.pxd text 22 | *.py text 23 | *.py3 text 24 | *.pyw text 25 | *.pyx text 26 | 27 | # Binary files 28 | # ============ 29 | *.db binary 30 | *.p binary 31 | *.pkl binary 32 | *.pyc binary 33 | *.pyd binary 34 | *.pyo binary 35 | 36 | # Note: .db, .p, and .pkl files are associated 37 | # with the python modules ``pickle``, ``dbm.*``, 38 | # ``shelve``, ``marshal``, ``anydbm``, & ``bsddb`` 39 | # (among others). -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | !__init__.py 2 | 3 | _src 4 | .vscode 5 | 6 | *.bak 7 | *.pyc 8 | *.qrc 9 | *.log 10 | *.stats 11 | 12 | *_DEBUG.sh 13 | *_DEBUG.bat 14 | 15 | config/users/* 16 | !config/users/arichter 17 | config/projects/* 18 | !config/projects/default 19 | 20 | exe/debug.py 21 | 22 | img/img_rc.py 23 | 24 | apps/extern/* 25 | 26 | software/max/plugins/* 27 | software/maya/plugins/* 28 | software/nuke/plugins/* 29 | software/houdini/plugins/* 30 | software/nuke/gizmos/extern 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | https://github.com/alexanderrichtertd/plex 2 | 3 | www.alexanderrichtertd.com 4 | contact@alexanderrichtertd.com 5 | 6 | ----------------------------------------------------------------------- 7 | 8 | The MIT License (MIT) 9 | 10 | Copyright (c) 2024 Alexander Richter 11 | 12 | This program is free software; you can redistribute it and/or modify it under 13 | the terms of the MIT License as published by the Open Source Initiative. 14 | 15 | This program is distributed in the hope that it will be useful, but WITHOUT 16 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | FOR A PARTICULAR PURPOSE. See the MIT License for more details. 18 | 19 | ----------------------------------------------------------------------- 20 | 21 | The binaries are linked against the following libraries: 22 | Qt.py (MIT) - https://github.com/mottosso/Qt.py 23 | Yaml (MIT) - https://pypi.python.org/pypi/PyYAML 24 | PySide (LGPL) - https://pypi.python.org/pypi/PySide 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > See the [**documentation**](https://github.com/alexanderrichtertd/plex/wiki),the [FMX 2017 Talk - Open Source Pipeline](https://www.youtube.com/watch?v=_JC0AMYX_Bw) and my **[YouTube Channel](https://youtube.com/alexanderrichtertd)**. 2 | 3 | ![splashscreen](https://user-images.githubusercontent.com/9514022/29427356-dbd29200-8389-11e7-9731-051ed39d2558.png) 4 | 5 | ## **Introduction** 6 | **Plex** is an **Visual Effects, Animation and Games pipeline** that manages critical workflows during production. 7 | Its core is a flexible and self-contained system for small to medium sized projects and companies. 8 | The basic idea is to manage the file and folder structure, set the ground rules and manage the workflow to allow collaboration in a complex production environment. Plug and play. 9 | 10 | > Intuitively guiding the input and output of users to overcome problems and achieve goals. 11 | > Now you have a good game ... or pipeline. 12 | 13 | [![plex_00_introduction](https://user-images.githubusercontent.com/9514022/29458175-179be8ba-841e-11e7-8be7-a83b0a37b28e.PNG)](https://youtu.be/gqRailvSmtw) 14 | 15 | ## Environment 16 | - [x] **OS**: Windows | Linux 17 | - [x] **Software**: Maya 2023+ | Houdini 19+ | 3ds Max 2023+ | Nuke 15+ | ... 18 | - [x] **Renderer**: Arnold | RenderMan | Mantra | V-Ray | ... 19 | 20 | ## Project Features 21 | - [x] visual effects, animation & game production management system 22 | - [x] file & folder management (settings | create | save | load | publish) 23 | - [x] flexible, portable, multi functional project environment 24 | - [x] additional libraries (api | img | user | shot) 25 | - [x] workflow tracking & reporting 26 | - [x] user-pipeline integration 27 | - [x] SSTP (simple | smart | transparent | performant) 28 | 29 | ![desktop_load](https://user-images.githubusercontent.com/9514022/30782643-477e0060-a136-11e7-883d-eadc16fbf0e0.gif) 30 | 31 | ## Pipeline Features 32 | - [x] **Scripts** 33 | - desktop app 34 | - save (+ publish) | load 35 | - get, set and handle config | img | scripts 36 | - template UI (user, report, help, accept, comment, color code) 37 | - setup menu, shelf, toolbar, ... 38 | - [x] **Workflows and Charts** 39 | - naming conventions 40 | - software pipeline 41 | - folder structure (project & pipeline) 42 | - [x] **Config and Helper** 43 | - project (resolution, fps ...) 44 | - user (name, task ...) 45 | - context (shot, task, comment ...) 46 | - environment variables (PROJECT_PATH ...) 47 | - additional libraries 48 | - [x] **Feedback & Debug** (+ advanced logging) 49 | - inform user about processes 50 | - debug like a king \*bow\* 51 | 52 | 53 | ## **Sponsor** 54 | [Become a sponsor](https://github.com/alexanderrichtertd/plex/wiki/Sponsor) and help us provide a better version of Plex. 55 | 56 | ## **Projects** 57 | - [Breaking Point](https://vimeo.com/178452618) \[VFX short film 2016\] 58 | [Winner VES Award 2017](https://www.visualeffectssociety.com/post/15th-annual-ves-awards-nominees) and [Winner Siggraph Asia 2016](https://sa2016.siggraph.org/en) 59 | - Elemental (Nuke) \[VFX short film 2016\] 60 | [FMX Trailer 2017](https://www.youtube.com/watch?v=KmI8yakN9d4) 61 | - [Animan](https://www.youtube.com/watch?v=CxxzeZg05mE) | [Drool Pool](https://www.youtube.com/watch?v=EueZW6H8Rq0&t=2s) 62 | 63 | 64 | ## **License** 65 | Plex is available under the **MIT License**. Use it for commercial or non-commercial projects. 66 | Be sure to credit me in the project and documentation. 67 | -------------------------------------------------------------------------------- /_project/0_pipeline/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/0_pipeline/meta/assetName_GEO_v002.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/_project/0_pipeline/meta/assetName_GEO_v002.jpg -------------------------------------------------------------------------------- /_project/0_pipeline/meta/s010_ANIM_v000.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/_project/0_pipeline/meta/s010_ANIM_v000.jpg -------------------------------------------------------------------------------- /_project/1_sandbox/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/1_sandbox/arichter/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/_references/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/animatic/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/concept_art/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/making_of/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/presentation/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/promotion/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/protocol/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/rnd/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/screenplay/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/2_preproduction/storyboard/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/3_footage/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/3_footage/hdri/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/3_footage/scene/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/3_footage/shader/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/3_footage/texture/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/assetName/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/assetName/GEO/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/assetName/RIG/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/assetName/RIG/PUBLISH/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/assetName/SHD/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_assets/assetName/SHD/PUBLISH/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/4_shots/.gitkeep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/deliver/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/edit/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/edit/cut/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/edit/music/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/edit/sound/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/grade/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/5_post/mov/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /_project/README.txt: -------------------------------------------------------------------------------- 1 | Project template folder 2 | 3 | UPDATE plex\config\project\{project name}\project.yml : PATH\project 4 | UPDATE other PATH if you changed directory names (30_assets, 40_shots, ...). 5 | -------------------------------------------------------------------------------- /apps/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/apps/__init__.py -------------------------------------------------------------------------------- /apps/arDesktop.py: -------------------------------------------------------------------------------- 1 | # content = OS startup file 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import sys 8 | import getpass 9 | import importlib 10 | 11 | from Qt import QtWidgets, QtGui, QtCore 12 | 13 | import plexfunc 14 | import plex 15 | 16 | LOG = plex.log(script=__name__) 17 | 18 | 19 | class SystemTrayIcon(QtWidgets.QSystemTrayIcon): 20 | 21 | def __init__(self, parent=None): 22 | QtWidgets.QSystemTrayIcon.__init__(self, parent) 23 | # self.activated.connect(self.showMainWidget) 24 | self.setIcon(QtGui.QIcon(plex.get_img_path('icons/p_yellow'))) 25 | self.parent = parent 26 | 27 | menu = QtWidgets.QMenu() 28 | menu.setStyleSheet(plex.config['script'][__name__]['style']) 29 | 30 | menuItem = menu.addAction(QtGui.QIcon(plex.get_img_path('user/default')), plex.user_id) 31 | menuItem.triggered.connect(self.press_btnShowUserSandbox) 32 | 33 | menuItem = menu.addAction(QtGui.QIcon(plex.get_img_path('icons/app_modify')), 'arConfig') 34 | menuItem.triggered.connect(self.press_btnConfigApp) 35 | 36 | menu.addSeparator() 37 | 38 | self.project_menu = QtWidgets.QMenu(plex.context['project_name']) 39 | self.project_menu.setStyleSheet(plex.config['script'][__name__]['style']) 40 | menu.addMenu(self.project_menu) 41 | 42 | for project in plex.project_names: 43 | selected_icon = plex.get_img_path('icons/check') if project == plex.context['project_id'] else '' 44 | menuItem = self.project_menu.addAction(QtGui.QIcon(selected_icon), project) 45 | menuItem.triggered.connect(self.press_btnChangeProject) 46 | 47 | # SUBMENU: software 48 | subMenu = QtWidgets.QMenu('Software') 49 | subMenu.setStyleSheet(plex.config['script'][__name__]['style']) 50 | menu.addMenu(subMenu) 51 | 52 | for soft, soft_func in plex.config['script'][__name__]['SOFTWARE'].items(): 53 | menuItem = subMenu.addAction(QtGui.QIcon(plex.get_img_path('software/default/' + soft)), soft.title()) 54 | menuItem.triggered.connect(eval(soft_func)) 55 | 56 | menu.addSeparator() 57 | 58 | menuItem = menu.addAction(QtGui.QIcon(plex.get_img_path('icons/load_yellow')), 'Load') 59 | menuItem.triggered.connect(self.press_btnLoad) 60 | 61 | menu.addSeparator() 62 | 63 | menuItem = menu.addAction(QtGui.QIcon(plex.get_img_path('icons/email_yellow')), 'Report') 64 | menuItem.triggered.connect(self.press_btnReport) 65 | 66 | menuItem = menu.addAction(QtGui.QIcon(plex.get_img_path('icons/help')), 'Help') 67 | menuItem.triggered.connect(self.press_btnHelp) 68 | 69 | menu.addSeparator() 70 | 71 | menuItem = menu.addAction(QtGui.QIcon(plex.get_img_path('icons/cancel')), 'Quit') 72 | menuItem.triggered.connect(self.press_closeStartup) 73 | 74 | self.setContextMenu(menu) 75 | 76 | 77 | # PRESS *********************************************************** 78 | def press_btnShowUserSandbox(self): 79 | plexfunc.open_dir(plex.config['project']['PATH']['sandbox'] + '/' + getpass.getuser()) 80 | 81 | def press_btnLoad(self): 82 | import arLoad 83 | importlib.reload(arLoad) 84 | self.arLoad = arLoad.ArLoad(desktop=True) 85 | 86 | #------------------------------ 87 | def press_btnOpenMaya(self): 88 | plex.software.start('maya') 89 | 90 | def press_btnOpenNuke(self): 91 | plex.software.start('nuke') 92 | 93 | def press_btnOpenHoudini(self): 94 | plex.software.start('houdini') 95 | 96 | def press_btnOpenMax(self): 97 | plex.software.start('max') 98 | 99 | #------------------------------ 100 | def press_btnOpenProjectConfig(self): 101 | plexfunc.open_dir(plex.paths['config_project']) 102 | 103 | def press_btnConfigApp(self): 104 | import arConfig 105 | arConfig.start() 106 | 107 | def press_btnChangeProject(self): 108 | LOG.debug('Change project') 109 | 110 | #------------------------------ 111 | def press_btnReport(self): 112 | plex.help('report') 113 | 114 | def press_btnHelp(self): 115 | plex.help(__name__) 116 | 117 | #------------------------------ 118 | def press_closeStartup(self): 119 | self.hide() 120 | self.setVisible(False) 121 | QtWidgets.QApplication.quit() 122 | 123 | 124 | # START *********************************************************** 125 | def start(): 126 | app = QtWidgets.QApplication.instance() 127 | if not app: app = QtWidgets.QApplication(sys.argv) 128 | app.setQuitOnLastWindowClosed(False) 129 | 130 | trayIcon = SystemTrayIcon(app) 131 | trayIcon.show() 132 | trayIcon.setToolTip(plex.config['plex']['name'] + ' [right click]') 133 | trayIcon.showMessage(plex.config['plex']['name'], '[right click]', 134 | QtWidgets.QSystemTrayIcon.Information , 20000) 135 | 136 | app.exec() 137 | -------------------------------------------------------------------------------- /apps/arNotice.py: -------------------------------------------------------------------------------- 1 | # content = informs artists about changes 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import webbrowser 9 | 10 | from threading import Timer 11 | from datetime import datetime 12 | 13 | from Qt import QtWidgets, QtGui, QtCore, QtCompat 14 | from Qt.QtCore import QPropertyAnimation, QEasingCurve 15 | 16 | import plex 17 | 18 | LOG = plex.log(script=__name__) 19 | 20 | 21 | class ArNotice(): 22 | def __init__(self, 23 | title = 'Notice', 24 | msg = 'This is a note test.', 25 | img = 'labels/default', 26 | img_link = 'https://www.alexanderrichtertd.com', 27 | duration = 8): 28 | 29 | # IGNORE arNotice if disabled 30 | if not plex.config['script']['arNotice']['enable']: return 31 | 32 | self.title = str(title) # Pipeline Update 33 | self.msg = str(msg) # New Features for Pipeline 34 | self.img = img # lbl/lblPreview131 35 | self.img_link = img_link # path 36 | self.time = datetime.now().strftime('%H:%M:%S %Y.%m.%d') 37 | self.duration = duration # 8 seconds 38 | 39 | ui_path = f"{os.path.dirname(__file__)}/{__name__}.ui" 40 | self.wgNotice = QtCompat.loadUi(ui_path) 41 | 42 | self.wgNotice.btnPreviewImg.clicked.connect(self.press_btnPreviewImg) 43 | 44 | self.wgNotice.edtTitle.setText(self.title) 45 | self.wgNotice.edtMsg.setPlainText(self.msg) 46 | 47 | self.wgNotice.edtTitle.setText(self.title) 48 | 49 | self.open_link = self.img_link 50 | self.wgNotice.btnPreviewImg.setToolTip(self.open_link) 51 | 52 | # if not os.path.exists(self.img): self.img = plex.get_img_path(self.img) 53 | self.wgNotice.btnPreviewImg.setIcon(QtGui.QPixmap(QtGui.QImage(self.img))) 54 | if not self.img_link: self.wgNotice.btnPreviewImg.setEnabled(False) 55 | 56 | # WIDGET : delete border & always on top 57 | self.wgNotice.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint) 58 | 59 | # Store screen dimensions 60 | self.screen_width, self.screen_height = QtWidgets.QApplication.screens()[0].size().toTuple() 61 | 62 | # Position top right corner 63 | self.final_x = self.screen_width - self.wgNotice.width() - 10 64 | self.final_y = 50 65 | 66 | # Set initial position (outside screen) 67 | self.wgNotice.move(self.screen_width, self.final_y) 68 | self.wgNotice.setWindowOpacity(0.95) 69 | 70 | # round edges 71 | path = QtGui.QPainterPath() 72 | path.addRoundedRect(QtCore.QRectF(self.wgNotice.rect()), 3.0, 3.0) 73 | self.wgNotice.setMask(QtGui.QRegion(path.toFillPolygon().toPolygon())) 74 | 75 | self.wgNotice.show() 76 | self.animate_window() 77 | self.start_duration() 78 | 79 | def animate_window(self): 80 | # Create animation for x position 81 | self.anim = QPropertyAnimation(self.wgNotice, b"pos") 82 | self.anim.setDuration(500) # Animation duration in milliseconds 83 | self.anim.setStartValue(QtCore.QPoint(self.screen_width, self.final_y)) 84 | self.anim.setEndValue(QtCore.QPoint(self.final_x, self.final_y)) 85 | self.anim.setEasingCurve(QEasingCurve.OutCubic) 86 | self.anim.start() 87 | 88 | def start_duration(self): 89 | if(self.duration): 90 | t = Timer(self.duration, self.end_process) 91 | t.start() 92 | 93 | def end_process(self): 94 | self.wgNotice.close() 95 | 96 | def press_btnPreviewImg(self): 97 | if self.img_link: 98 | webbrowser.open(os.path.realpath(self.img_link)) 99 | 100 | def __call__(self): 101 | LOG.debug('title: ' + self.title + '\n' +\ 102 | 'msg: ' + self.msg + '\n' +\ 103 | 'img: ' + self.img + '\n' +\ 104 | 'img_link: ' + self.img_link 105 | ) -------------------------------------------------------------------------------- /apps/arNotice.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Form 4 | 5 | 6 | 7 | 0 8 | 0 9 | 356 10 | 80 11 | 12 | 13 | 14 | 15 | 356 16 | 80 17 | 18 | 19 | 20 | 21 | 356 22 | 80 23 | 24 | 25 | 26 | Form 27 | 28 | 29 | QWidget{ 30 | color: rgb(201, 202, 204); 31 | background-color: rgb(38, 38, 38); 32 | selection-background-color: rgb(1, 79, 131); 33 | } 34 | 35 | QListWidget::item:selected{ 36 | color: rgb(235, 235, 235); 37 | background-color: rgb(61, 120, 200); 38 | } 39 | 40 | QPushButton { 41 | border: 2px; 42 | border-color: rgb(33, 33, 33); 43 | border-radius: 3px; 44 | background-color: rgb(49, 49, 49); 45 | } 46 | 47 | QPushButton:hover { 48 | border-radius: 3px; 49 | color: rgb(49, 49, 49); 50 | background-color: rgb(200, 184, 86); 51 | } 52 | 53 | QToolTip { 54 | border-radius: 5px; 55 | background-color: rgb(33, 33, 33); 56 | color: rgb(241, 241, 241); 57 | border: black solid 1px; 58 | } 59 | 60 | 61 | 62 | 12 63 | 64 | 65 | 0 66 | 67 | 68 | 0 69 | 70 | 71 | 0 72 | 73 | 74 | 75 | 76 | 77 | 140 78 | 80 79 | 80 | 81 | 82 | 83 | 140 84 | 80 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | :/label/labels/default.png:/label/labels/default.png 93 | 94 | 95 | 96 | 140 97 | 80 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 0 106 | 107 | 108 | 10 109 | 110 | 111 | 8 112 | 113 | 114 | 115 | 116 | 117 | 75 118 | true 119 | 120 | 121 | 122 | padding: 2px 123 | 124 | 125 | LOAD: s140_RIG_v001.mb 126 | 127 | 128 | false 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 16777215 137 | 44 138 | 139 | 140 | 141 | QFrame::NoFrame 142 | 143 | 144 | 0 145 | 146 | 147 | Qt::ScrollBarAlwaysOff 148 | 149 | 150 | Qt::ScrollBarAlwaysOff 151 | 152 | 153 | false 154 | 155 | 156 | true 157 | 158 | 159 | Lorem Ipsum is simply dummy text of the printing and typesetting industry. 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /apps/arSplash.py: -------------------------------------------------------------------------------- 1 | # content = splash screen 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | 9 | from Qt import QtWidgets, QtGui, QtCore, QtCompat 10 | 11 | import plex 12 | 13 | LOG = plex.log(script=__name__) 14 | 15 | 16 | class ArSplash(): 17 | def __init__(self): 18 | ui_path = f"{os.path.dirname(__file__)}/{__name__}.ui" 19 | self.wgSplash = QtCompat.loadUi(ui_path) 20 | 21 | # SKIP splash 22 | if not plex.config['plex']['splash']: return 23 | 24 | self.wgSplash.setWindowFlags(QtCore.Qt.CustomizeWindowHint | QtCore.Qt.FramelessWindowHint | QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint) 25 | self.wgSplash.setAttribute(QtCore.Qt.WA_TranslucentBackground) 26 | 27 | # drop shadow effect 28 | self.shadow = QtWidgets.QGraphicsDropShadowEffect(self.wgSplash.fraSplash) 29 | self.shadow.setBlurRadius(20) 30 | self.shadow.setXOffset(0) 31 | self.shadow.setYOffset(0) 32 | self.shadow.setColor(QtGui.QColor(0, 0, 0, 60)) 33 | 34 | self.wgSplash.lblName.setText(plex.context['name']) 35 | self.wgSplash.lblDescription.setText(plex.context['description']) 36 | self.wgSplash.lblVersion.setText(plex.context['version']) 37 | 38 | # TIMER 39 | self.timer = QtCore.QTimer() 40 | self.timer.timeout.connect(self.progress) 41 | self.timer.start(10) 42 | self.counter = 0 43 | 44 | self.wgSplash.show() 45 | LOG.debug('START : arSplash') 46 | 47 | def progress(self): 48 | self.wgSplash.progressBar.setValue(self.counter) 49 | 50 | if self.counter > 100: 51 | self.timer.stop() 52 | self.wgSplash.close() 53 | 54 | self.counter += 1 55 | -------------------------------------------------------------------------------- /apps/arSplash.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | SplashScreen 4 | 5 | 6 | 7 | 0 8 | 0 9 | 460 10 | 278 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 0 20 | 21 | 22 | 10 23 | 24 | 25 | 10 26 | 27 | 28 | 10 29 | 30 | 31 | 10 32 | 33 | 34 | 35 | 36 | QFrame { 37 | background-color: rgb(33, 33, 33); 38 | color: rgb(220, 220, 220); 39 | border-radius: 10px; 40 | } 41 | 42 | 43 | QFrame::StyledPanel 44 | 45 | 46 | QFrame::Raised 47 | 48 | 49 | 50 | 51 | 0 52 | 55 53 | 441 54 | 91 55 | 56 | 57 | 58 | 59 | Segoe UI 60 | 50 61 | 75 62 | true 63 | 64 | 65 | 66 | color: rgb(221, 191, 133); 67 | 68 | 69 | <html><head/><body><p>PLEX</p></body></html> 70 | 71 | 72 | Qt::AlignCenter 73 | 74 | 75 | 76 | 77 | 78 | 0 79 | 125 80 | 441 81 | 31 82 | 83 | 84 | 85 | 86 | Segoe UI 87 | 12 88 | 89 | 90 | 91 | color: rgb(221, 191, 133); 92 | background-color: rgba(255, 255, 255, 0%); 93 | 94 | 95 | <html><head/><body><p>Open Source Pipeline</p></body></html> 96 | 97 | 98 | Qt::AlignCenter 99 | 100 | 101 | 102 | 103 | 104 | 0 105 | 235 106 | 441 107 | 23 108 | 109 | 110 | 111 | 112 | 10 113 | 114 | 115 | 116 | QProgressBar { 117 | background-color: rgba(133, 163, 221, 20%); 118 | color: rgb(250, 250, 250); 119 | border-style: none; 120 | border-radius: 6px; 121 | border-top-left-radius: 0px; 122 | border-top-right-radius: 0px; 123 | text-align: center; 124 | } 125 | QProgressBar::chunk{ 126 | border-radius: 6px; 127 | border-top-left-radius: 0px; 128 | background-color: qlineargradient(spread:pad, x1:0, y1:0.511364, x2:1, y2:0.523, stop:0 rgb(221, 191, 133), stop:1 rgb(200, 184, 86)); 129 | } 130 | 131 | 132 | 24 133 | 134 | 135 | false 136 | 137 | 138 | 139 | 140 | 141 | 0 142 | 155 143 | 441 144 | 21 145 | 146 | 147 | 148 | 149 | Segoe UI 150 | 10 151 | 152 | 153 | 154 | color: rgb(200, 200, 200); 155 | 156 | 157 | <html><head/><body><p>Alexander Richter</p></body></html> 158 | 159 | 160 | Qt::AlignCenter 161 | 162 | 163 | 164 | 165 | 166 | 0 167 | 230 168 | 441 169 | 31 170 | 171 | 172 | 173 | 174 | Segoe UI 175 | 10 176 | 177 | 178 | 179 | color: rgb(230, 230, 230); 180 | background-color: rgba(255, 255, 255, 0%); 181 | 182 | 183 | <html><head/><body><p>2.5.0</p></body></html> 184 | 185 | 186 | Qt::AlignCenter 187 | 188 | 189 | progressBar 190 | lblVersion 191 | lblName 192 | lblDescription 193 | lblCredit 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | -------------------------------------------------------------------------------- /apps/arUtil.py: -------------------------------------------------------------------------------- 1 | # content = parent widget 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import sys 9 | 10 | from Qt import QtWidgets, QtGui, QtCore, QtCompat 11 | 12 | import plexfunc 13 | import plex 14 | 15 | LOG = plex.log(script=__name__) 16 | 17 | 18 | class ArUtil(object): 19 | 20 | def __init__(self): 21 | ui_path = f"{os.path.dirname(__file__)}/{__name__}.ui" 22 | self.wgHeader = QtCompat.loadUi(ui_path) 23 | 24 | # IMPORTANT variables 25 | self.open_path = "" 26 | 27 | 28 | self.wgHeader.setWindowIcon(QtGui.QPixmap(QtGui.QImage(plex.get_img_path("icons/app_modify")))) 29 | 30 | # BUTTONS ICONS 31 | self.wgHeader.btnReport.setIcon(QtGui.QPixmap(QtGui.QImage(plex.get_img_path("icons/email")))) 32 | self.wgHeader.btnHelp.setIcon(QtGui.QPixmap(QtGui.QImage(plex.get_img_path("icons/help")))) 33 | self.wgHeader.btnOpenFolder.setIcon(QtGui.QPixmap(QtGui.QImage(plex.get_img_path("icons/folder_open")))) 34 | self.wgHeader.btnUser.setIcon(QtGui.QPixmap(QtGui.QImage(plex.get_img_path("user/default")))) # current user 35 | self.wgHeader.btnUser.setToolTip("".join(['

', 36 | plex.user_id, '
', 37 | 'Admin' if plex.admin else 'Artist', '
[open user sandbox]

'])) 38 | 39 | self.wgHeader.btnProject.setIcon(QtGui.QPixmap(QtGui.QImage(plex.get_img_path('icons/project2')))) # current user 40 | self.wgHeader.btnProject.setToolTip(plex.context['project_name'] + '\n[open project folder]') 41 | 42 | # SIGNAL 43 | self.wgHeader.btnAccept.clicked.connect(self.press_btnAccept) 44 | self.wgHeader.btnAccept.setAttribute(QtCore.Qt.WA_TranslucentBackground) 45 | 46 | self.wgHeader.btnOpenFolder.clicked.connect(self.press_btnOpenFolder) 47 | self.wgHeader.btnUser.clicked.connect(self.press_btnUser) 48 | self.wgHeader.btnProject.clicked.connect(self.press_btnProject) 49 | self.wgHeader.btnReport.clicked.connect(self.press_btnReport) 50 | self.wgHeader.btnHelp.clicked.connect(self.press_btnHelp) 51 | 52 | # SHOW announcement from project or (if not existing) plex 53 | self.wgHeader.lblAnnouncement.setText(plex.announcement) 54 | 55 | # SETUP 56 | self.wgHeader.setWindowIcon(QtGui.QIcon(plex.get_img_path("icons/program"))) 57 | self.wgHeader.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint) 58 | 59 | # NEED to show in used app to avoid double popup 60 | # self.wgHeader.show() 61 | 62 | 63 | # PRESS *************************************************************** 64 | def press_btnAccept(self): 65 | print('PRESS accept') 66 | 67 | def press_btnOpenFolder(self): 68 | plexfunc.open_dir(self.open_path) 69 | 70 | def press_btnUser(self): 71 | plexfunc.open_dir(plex.user_sandbox) 72 | 73 | def press_btnProject(self): 74 | plexfunc.open_dir(plex.config['project']['PATH']['project']) 75 | 76 | def press_btnReport(self): 77 | plex.help('report') 78 | 79 | def press_btnHelp(self, name=__name__): 80 | plex.help(name) 81 | 82 | 83 | # FUNCTION *************************************************************** 84 | def set_progress(self, count=0): 85 | self.wgHeader.prbStatus.setValue(count) 86 | 87 | def set_announcement(self, comment): 88 | self.wgHeader.lblAnnouncement.setText(comment) 89 | LOG.info(comment) 90 | 91 | def resize_widget(self, widget): 92 | x = widget.frameGeometry().width() 93 | y = self.wgHeader.frameGeometry().height() + widget.frameGeometry().height() - 40 94 | self.wgHeader.resize(x, y) 95 | self.wgHeader.setMinimumSize(x, y) 96 | 97 | 98 | # START *************************************************************** 99 | def start(): 100 | app = QtWidgets.QApplication(sys.argv) 101 | util = ArUtil() 102 | app.exec_() -------------------------------------------------------------------------------- /config/plex.yml: -------------------------------------------------------------------------------- 1 | # content = plex config 2 | # date = 01.01.2025 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | name: Plex 8 | description: Open Source Pipeline 9 | version: 2.5.0 10 | 11 | url: https://github.com/alexanderrichtertd/plex 12 | credit: Alexander Richter 13 | 14 | # ANNOUNCEMENT shown in every application if set 15 | announcement: Plex 2.5.0 16 | 17 | # Show splash screen on startup 18 | splash: True 19 | 20 | # ADMIN special rights (user_id) 21 | admin: 22 | - alexa 23 | - arichter 24 | STATUS: 25 | work: WORK 26 | publish: PUBLISH 27 | render: RENDER 28 | 29 | EXTENSION: 30 | maya: ma 31 | max: max 32 | nuke: nk 33 | houdini: hipnc 34 | photoshop: psd 35 | substance: spp 36 | 37 | playblast: mov 38 | texture: exr 39 | render: exr 40 | thumbnail: jpg 41 | 42 | icons: png 43 | -------------------------------------------------------------------------------- /config/projects/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /config/projects/default/meta.yml: -------------------------------------------------------------------------------- 1 | !!python/unicode 'assetName_GEO_v002.ma': 2 | file_path: 3 | img_path: 4 | 5 | comment: Created an olive with paprika. 6 | user: arichter 7 | 8 | 9 | !!python/unicode 's010_ANIM_v000.ma': 10 | comment: adding light and shader 11 | user: alexa 12 | 13 | -------------------------------------------------------------------------------- /config/projects/default/project.yml: -------------------------------------------------------------------------------- 1 | # content = project config 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | active: True 8 | name: Plex Project 9 | 10 | # ANNOUNCEMENT shown in every application 11 | announcement: 12 | 13 | #********************************************************************* 14 | SETTING: 15 | frame_start: 1001 16 | 17 | resolution: 18 | - 1920 19 | - 1080 20 | fps: 24 21 | 22 | renderer: arnold 23 | 24 | #********************************************************************* 25 | PATH: 26 | project : &PROJECT $plex/_project 27 | 28 | pipeline : !join [*PROJECT, /0_pipeline] 29 | meta : !join [*PROJECT, /0_pipeline/meta] 30 | 31 | sandbox : !join [*PROJECT, /1_sandbox] 32 | preproduction : !join [*PROJECT, /2_preproduction] 33 | footage : !join [*PROJECT, /3_footage] 34 | 35 | assets : !join [*PROJECT, /4_assets] 36 | shots : !join [*PROJECT, /4_shots] 37 | 38 | post : !join [*PROJECT, /5_post] 39 | 40 | # sq010_sky/s020_angle/RIG/WORK/s020_angle_RIG_v001.mb 41 | # items.format(seq='sq010_sequence', entity='s010_shot', 42 | # task='RIG', status='WORK', version='v001', 43 | # frame='1001', user='ar', extension='mb') 44 | file_structure: "{entity}/{task}/{status}/{entity}_{task}_{version}.{extension}" 45 | 46 | # replace if with sequences 47 | # shots : "{sequence}/{entity}/{task}/{status}/{entity}_{task}_{version}.{extension}" 48 | # render: "{sequence}/{entity}/{task}/{status}/{entity}_{task}_{version}.{frame}.{extension}" 49 | 50 | #********************************************************************* 51 | URL: 52 | default: &WIKI https://github.com/alexanderrichtertd/plex/wiki 53 | 54 | arUtil: !join [*WIKI, /arUtil] 55 | arDesktop: !join [*WIKI, /arDesktop] 56 | arSave: !join [*WIKI, /arSave] 57 | arNotice: !join [*WIKI, /arNotice] 58 | 59 | shelf: !join [*WIKI, /shelf] 60 | report: !join [*WIKI, /report] 61 | -------------------------------------------------------------------------------- /config/projects/default/script.yml: -------------------------------------------------------------------------------- 1 | # content = scripts 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | # seperate with comma: save,report 8 | 9 | # enable: True|False 10 | # software: os, maya, max, nuke, houdini, c4d, blender 11 | 12 | #********************************************************************* 13 | arUtil: 14 | progress_color: 15 | - lightblue 16 | - lightgreen 17 | - orange 18 | - red 19 | progress_img: 20 | - btn/btn_write 21 | - btn/btn_accept 22 | - btn/btn_warning 23 | - btn/btn_denial 24 | #********************************************************************* 25 | arNotice: 26 | enable: True 27 | timer: 7 28 | 29 | #********************************************************************* 30 | arSave: 31 | start: &arSave import arSave; arSave.start() 32 | img: &arSave_img png, jpg, tiff 33 | just_screenshot: True 34 | 35 | #********************************************************************* 36 | arLoad: 37 | img: *arSave_img 38 | close_after: True 39 | 40 | #********************************************************************* 41 | arDesktop: 42 | auto_start: True 43 | style: "color: rgb(200, 200, 200);background-color: rgb(26, 30, 33);selection-background-color: rgb(60, 110, 190);" 44 | 45 | SOFTWARE: 46 | maya: self.press_btnOpenMaya 47 | max: self.press_btnOpenMax 48 | nuke: self.press_btnOpenNuke 49 | houdini: self.press_btnOpenHoudini 50 | 51 | #********************************************************************* 52 | arWrite: 53 | renderthreads: 12 54 | 55 | achievement: 56 | enable: True 57 | 58 | # pipeline kid 59 | script_report: 60 | - 20 61 | - 100 62 | - 500 63 | # unbreakable 64 | script_crash: 65 | - 20 66 | - 100 67 | - 500 68 | -------------------------------------------------------------------------------- /config/projects/default/software/houdini.yml: -------------------------------------------------------------------------------- 1 | # content = Houdini config 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | version: &HOUDINI_VERSION 19.5.773 8 | path: &HOUDINI_PATH !join ["C:/Program Files/Side Effects Software/Houdini ", *HOUDINI_VERSION, /bin/houdini.exe] 9 | 10 | start: *HOUDINI_PATH 11 | 12 | # renderer: 13 | # renderer_path: 14 | 15 | 16 | ENV: 17 | PYTHONPATH: 18 | - $software 19 | - $software/scripts 20 | - $software/apps 21 | 22 | # HOUDINI_USER_PREF_DIR: 23 | # - $config_project/houdini] 24 | # HOUDIN_PATH: 25 | # - $config_project/houdini] 26 | 27 | HOUDINI_SPLASH_FILE: $img/software/houdini/houdini_splash.png 28 | 29 | # MENU: plex/config/$project/houdini/MainMenuMaster.xml 30 | 31 | # SETTINGS: 32 | -------------------------------------------------------------------------------- /config/projects/default/software/max.yml: -------------------------------------------------------------------------------- 1 | # content = 3ds Max config 2 | # date = 2020-06-19 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | version: &MAX_VERSION 2023 8 | path: &MAX_PATH !join ["C:/Program Files/Autodesk/3ds Max ", *MAX_VERSION, /3dsmax.exe] 9 | 10 | start: *MAX_PATH 11 | 12 | # renderer: 13 | # renderer_path: 14 | 15 | ENV: 16 | PYTHONPATH: 17 | - $software 18 | - $software/scripts 19 | - $software/apps 20 | - $software/icons 21 | 22 | # ADSKFLEX_LICENSE_FILE: 23 | 24 | 25 | #********************************************************************* 26 | # MENU 27 | #********************************************************************* 28 | # MENU: 29 | # - plex: 30 | # - open_scene_folder: AddItem(MaxPlus.ActionFactory.Create('Open Scene Folder', 'Open Scene Folder', max_dcc.Max().open_scene_folder)) 31 | # - open_project_folder: AddItem(MaxPlus.ActionFactory.Create('Open Project Folder', 'Open Project Folder', max_dcc.Max().open_project_folder)) 32 | 33 | # - break: AddSeparator() 34 | 35 | # - Save: AddItem(MaxPlus.ActionFactory.Create('Save', 'Save', max_dcc.Max().save)) 36 | # - Load: AddItem(MaxPlus.ActionFactory.Create('Load', 'Load', max_dcc.Max().load)) 37 | 38 | # - break: AddSeparator() 39 | 40 | # - Report: "AddItem(MaxPlus.ActionFactory.Create('Report', 'Report', max_dcc.Max().report))" 41 | # - Help: "AddItem(MaxPlus.ActionFactory.Create('Help', 'Help', max_dcc.Max().help))" 42 | 43 | 44 | # SETTINGS: 45 | -------------------------------------------------------------------------------- /config/projects/default/software/maya.yml: -------------------------------------------------------------------------------- 1 | # content = Maya config 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | version: &MAYA_VERSION 2023 8 | path: &MAYA_PATH !join ["C:/Program Files/Autodesk/Maya", *MAYA_VERSION, /bin/maya.exe] 9 | 10 | # start command 11 | start: !join ['start "" "', *MAYA_PATH, '" {}'] 12 | 13 | # renderer: 14 | # renderer_path: 15 | 16 | # Added BEFORE software starts 17 | ENV: 18 | MAYA_SCRIPT_PATH: 19 | - $software/maya/scripts 20 | 21 | MAYA_PLUG_IN_PATH: 22 | - $software/maya/apps 23 | 24 | # MAYA_SHELF_PATH: 25 | # - $software/maya/scripts 26 | 27 | # SPLASHSCREEN & IMG PATH 28 | XBMLANGPATH: 29 | - $img/software/maya 30 | 31 | # DISABLE close reports 32 | MAYA_DISABLE_CIP: 1 33 | MAYA_DISABLE_CER: 1 34 | 35 | 36 | 37 | #********************************************************************* 38 | # MENU 39 | #********************************************************************* 40 | MENU: 41 | - $project_name: 42 | - Open Scene Folder: import plexfunc; plexfunc.open_dir(cmds.file(q=True, sceneName=True)) 43 | - Open Project Folder: import plexfunc; plexfunc.open_dir(plex.config['project']['PATH']['project']) 44 | - break: 45 | - Reload Pipeline: print('reload pipeline') 46 | 47 | - break: 48 | 49 | - Save: import arSave; arSave.start() 50 | - Load: import arLoad; arLoad.start() 51 | 52 | - break: 53 | 54 | - Animation: 55 | - Playblast: from ANIM import playblast;playblast.start() 56 | 57 | - Light: 58 | - Light Linker: from LGT import light_linker;import importlib;importlib.reload(light_linker);light_linker.start() 59 | 60 | - Render: 61 | - Rendersetting - Work: plex.scene_setup("render", "work") 62 | - Rendersetting - Publish: plex.scene_setup("render", "publish") 63 | 64 | - break: 65 | 66 | - Report: import plex; plex.help("report") 67 | - Help: import plex; plex.help() 68 | 69 | 70 | 71 | # #********************************************************************* 72 | # # SHELF 73 | # #********************************************************************* 74 | # SHELF: 75 | # HEADER: 76 | # - save: l="Save", command="import arSave; import importlib;importlib.reload(arSave); arSave.start()", dcc=", image="shelf_save.png" 77 | # - load: l="Load", command="import arLoad; import importlib;importlib.reload(arLoad); arLoad.start()", dcc=", image="shelf_load.png" 78 | # - break: width=1, l="break", command="print("empty")", dcc=", image="separator.png" 79 | 80 | # - folder: l="Project Folder", command="import webbrowser; webbrowser.open(os.path.dirname(plex.software.scene_path))", dcc=", image="shelf_open_dir.png" 81 | # - folder: l="Project Folder", command="import plexfunc; plexfunc.open_dir(plex.config['project']["path"])", dcc=", image="shelf_open_dir_project.png" 82 | 83 | # - break: width=1, l="break", command="print("empty")", dcc=", image="separator.png" 84 | 85 | # FOOTER: 86 | # - break: width=1, l="break", command="print("empty")", dcc=", image="separator.png" 87 | 88 | # - rs_publish: l="Rendersetting - Work", command="plex.software.scene_setup("RENDER", "WORK")", dcc=", image="shelf_render_work.png" 89 | # - rs_publish: l="Rendersetting - Preview", command="plex.software.scene_setup("RENDER", "PREVIEW")", dcc=", image="shelf_render_preview.png" 90 | # - rs_publish: l="Rendersetting - Publish", command="plex.software.scene_setup("RENDER", "DELIVER")", dcc=", image="shelf_render_deliver.png" 91 | 92 | # - break: width=1, l="break", command="print("empty")", dcc=", image="separator.png" 93 | 94 | # - report: l="Report", command="import plex;plex.help("report")", dcc=", image="shelf_report.png" 95 | # - help: l="Help", command="import plex;plex.help()", dcc=", image="shelf_help.png" 96 | 97 | # #***************************************************************************************************************************** 98 | 99 | # GEO: 100 | # - temp: l="Nothing", command="print("nothing")", dcc=", image="shelf_default.png" 101 | 102 | # SHD: 103 | # - temp: l="Nothing", command="print("nothing")", dcc=", image="shelf_default.png" 104 | 105 | # RIG: 106 | # - temp: l="Nothing", command="print("nothing")", dcc=", image="shelf_default.png" 107 | 108 | # LAY: 109 | # - snap: l="Snap to first selection", command="import maya_utils;import importlib;importlib.reload(maya_utils); maya_utils.position_selected()", dcc=", image="shelf_snap.png" 110 | # - playblast: l="Playblast", command="from ANIM import playblast;import importlib;importlib.reload(playblast); playblast.start()", dcc=", image="shelf_playblast.png" 111 | 112 | # ANIM: 113 | # - snap: l="Snap to first selection", command="import maya_utils;import importlib;importlib.reload(maya_utils); maya_utils.position_selected()", dcc=", image="shelf_snap.png" 114 | # - playblast: l="Playblast", command="from ANIM import playblast;import importlib;importlib.reload(playblast); playblast.start()", dcc=", image="shelf_playblast.png" 115 | 116 | # LIGHT: 117 | # - render_work: l="Rendersettings - Work", command="plex.software.scene_setup("RENDER", WORK")", dcc=", image="shelf_render_work.png" 118 | # - render_preview: l="Rendersettings - Work", command="plex.software.scene_setup("RENDER", "PREVIEW")", dcc=", image="shelf_render_preview.png" 119 | # - render_deliver: l="Rendersettings - Work", command="plex.software.scene_setup("RENDER", "DELIVER")", dcc=", image="shelf_render_deliver.png" 120 | # - break: width=1, l="break", command="print("empty")", dcc=", image="separator.png" 121 | # - light_linker: l="Light Linker", command="from LGT import light_linker;import importlib;importlib.reload(light_linker);light_linker.start()", dcc=", image="shelf_light_linker.png" 122 | 123 | 124 | 125 | # #********************************************************************* 126 | # # RENDER 127 | # #********************************************************************* 128 | # RENDER: 129 | 130 | # DEFAULT: 131 | # # - defaultArnoldRenderOptions.AASamples: 2 132 | # - " : " 133 | 134 | # WORK: 135 | # - " : " 136 | 137 | 138 | # PREVIEW: 139 | # - " : " 140 | 141 | 142 | # DELIVER: 143 | # - " : " 144 | 145 | 146 | # CUSTOM: 147 | # - " : " 148 | 149 | 150 | 151 | # #********************************************************************* 152 | # # SETUP 153 | # #********************************************************************* 154 | # SETUP: 155 | 156 | # DEFAULT: 157 | # # - defaultResolution.width : plex.config['project']["resolution"][0] 158 | # # - defaultResolution.height : plex.config['project']["resolution"][1] 159 | 160 | # - defaultRenderGlobals.animation : 1 161 | # - defaultRenderGlobals.putFrameBeforeExt : 1 162 | # - defaultRenderGlobals.extensionPadding : 4 163 | # # - FPS : 24: film 164 | # # - unit : cm 165 | 166 | # GEO: 167 | 168 | 169 | # SHD: 170 | 171 | 172 | # RIG: 173 | 174 | 175 | # LAY: 176 | 177 | 178 | # ANIM: 179 | 180 | 181 | # LIGHT: 182 | 183 | 184 | 185 | # #********************************************************************* 186 | # # EXTRAS 187 | # #********************************************************************* 188 | # GROUPS: 189 | # ANIM_GRP: 190 | # - char_GRP 191 | # - props_GRP 192 | # - fx_GRP 193 | # LAYOUT: 194 | # - props_GRP 195 | # - sets_GRP 196 | # CAM_GRP: 197 | # - " 198 | # REVIEW_GRP: 199 | # - proxy_GRP 200 | # - playblast_GRP 201 | -------------------------------------------------------------------------------- /config/projects/default/software/nuke.yml: -------------------------------------------------------------------------------- 1 | # content = Nuke config 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | version: &NUKE_VERSION 15.1 8 | version_long: &NUKE_VERSION_LONG !join [*NUKE_VERSION, v1] 9 | 10 | start: !join ['start "" Nuke', *NUKE_VERSION ,'.exe --nukex {}'] 11 | 12 | path: !join ["C:/Program Files/Nuke", *NUKE_VERSION_LONG,/Nuke, *NUKE_VERSION, .exe] 13 | 14 | 15 | ENV: 16 | PYTHONPATH: 17 | - $software/scripts 18 | - $software/apps 19 | - $software/gizmos 20 | 21 | NUKE_PATH: 22 | - $plex 23 | - $software 24 | # - STATUS_PATH 25 | # - PLUGIN_PATH 26 | 27 | # Init & Menu 28 | NUKE_INIT_PATH: $software 29 | NUKE_MENU_PATH: $software 30 | 31 | NUKE_DIR: &NUKE_DIR !join ["C:/Program Files/Nuke", *NUKE_VERSION_LONG] 32 | 33 | PATH: *NUKE_DIR 34 | 35 | 36 | #********************************************************************* 37 | # MENU 38 | #********************************************************************* 39 | # MENU: 40 | # - Plex: 41 | # open_scene_folder: addCommand('Open Scene Folder', 'import plexfunc; plexfunc.open_dir(nuke.root().knob("name").value())') 42 | # open_project_folder: addCommand('Open Project Folder', 'import plexfunc; plexfunc.open_dir(plex.config['project']["path"])') 43 | 44 | # - break: addSeparator() 45 | 46 | # - Save: "addCommand('Save', 'import menu; save()', 'ctrl+alt+s', 'save.ico')" 47 | # - Load: "addCommand('Load', 'import menu; load()', 'ctrl+alt+l', 'load.ico')" 48 | 49 | # - break: "addSeparator()" 50 | 51 | # - arWrite: addCommand('arWrite', 'arWrite()', 'ctrl+alt+w', 'write.ico') 52 | 53 | # - break: addSeparator() 54 | 55 | # - Report: addCommand('Report', 'import plexfunc; plexfunc.help("report")', 'ctrl+alt+r', 'report.ico') 56 | # - Help: addCommand('Help', 'import plexfunc; plexfunc.help()', 'ctrl+alt+h', 'help.ico') 57 | 58 | # SETTINGS: 59 | -------------------------------------------------------------------------------- /config/users/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /config/users/arichter/user.yml: -------------------------------------------------------------------------------- 1 | # content = user config 2 | # date = 2020-06-19 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | name: Alexander Richter 8 | id: alexa 9 | position: Technical Director 10 | 11 | rights: 'admin' 12 | 13 | 14 | # REPOSITORY ********************************************************** 15 | REPOSITORY: 16 | username: guest 17 | password: 18 | 19 | owner: alexanderrichtertd 20 | repository: plex 21 | -------------------------------------------------------------------------------- /exe/.keep: -------------------------------------------------------------------------------- 1 | "" 2 | -------------------------------------------------------------------------------- /exe/linux/Desktop.sh: -------------------------------------------------------------------------------- 1 | :: arDESKTOP 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | CALL %~dp0\setup_env.bat 7 | 8 | start "" pythonw %newDir%\plex.py %1 --software desktop 9 | 10 | exit 11 | -------------------------------------------------------------------------------- /exe/linux/Maya.sh: -------------------------------------------------------------------------------- 1 | :: MAYA 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | CALL %~dp0\setup_env.bat 7 | 8 | pythonw %newDir%\plex.py %1 --software maya 9 | 10 | exit 11 | -------------------------------------------------------------------------------- /exe/linux/setup_env.sh: -------------------------------------------------------------------------------- 1 | :: SETUP external packages 2 | 3 | set "newDir=%~dp0\..\..\config" 4 | :: set "PYTHONPATH=%~dp0;%~dp0\github" 5 | -------------------------------------------------------------------------------- /exe/windows/3dsMax.bat: -------------------------------------------------------------------------------- 1 | :: 3DsMax 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | python "%~dp0/../../scripts/plexstart.py" %1 --software max 7 | 8 | exit 9 | -------------------------------------------------------------------------------- /exe/windows/desktop.bat: -------------------------------------------------------------------------------- 1 | :: arDESKTOP 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | :: Check Python version 7 | call "%~dp0\python_check.bat" 8 | if %errorlevel% neq 0 (exit /b %errorlevel%) 9 | 10 | python "%~dp0/../../scripts/plexstart.py" %1 --software desktop 11 | 12 | exit 13 | -------------------------------------------------------------------------------- /exe/windows/houdini.bat: -------------------------------------------------------------------------------- 1 | :: HOUDINI 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | python "%~dp0/../../scripts/plexstart.py" %1 --software houdini 7 | 8 | exit 9 | 10 | -------------------------------------------------------------------------------- /exe/windows/maya.bat: -------------------------------------------------------------------------------- 1 | :: MAYA 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | python "%~dp0/../../scripts/plexstart.py" %1 --software maya 7 | 8 | exit 9 | -------------------------------------------------------------------------------- /exe/windows/nuke.bat: -------------------------------------------------------------------------------- 1 | :: NUKE 2 | 3 | :: Hide Commands 4 | @echo off 5 | 6 | python "%~dp0/../../scripts/plexstart.py" %1 --software nuke 7 | 8 | exit 9 | 10 | -------------------------------------------------------------------------------- /exe/windows/python_check.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal EnableDelayedExpansion 3 | 4 | :: Check if Python is in the PATH 5 | for /f "delims=" %%i in ('where python') do ( 6 | echo %%i | findstr /I "Microsoft\\WindowsApps" >NUL 7 | if !errorlevel! equ 0 ( 8 | echo Found invalid Python at: %%i 9 | ) else ( 10 | set "PYTHON_PATH=%%i" 11 | goto :CheckVersion 12 | ) 13 | ) 14 | 15 | if not defined PYTHON_PATH ( 16 | echo Python is not in the PATH. 17 | echo Please install Python and add it to the PATH. 18 | exit /b 1 19 | ) 20 | 21 | :CheckVersion 22 | :: Check if Python version is 3.6 or higher 23 | for /f "delims=" %%v in ('"%PYTHON_PATH%" --version 2^>^&1') do ( 24 | set "PYTHON_VERSION=%%v" 25 | goto :VersionFound 26 | ) 27 | 28 | :VersionFound 29 | echo !PYTHON_VERSION! | findstr /R "^Python 3\.\(6\|[7-9]\|\d{2,}\)" >NUL 30 | if !errorlevel! neq 0 ( 31 | echo Please install Python 3.6 or higher: www.python.org 32 | exit /b 1 33 | ) 34 | 35 | echo !PYTHON_VERSION! is installed and meets requirements (Python 3.6+). 36 | echo. 37 | 38 | :: exit /b 0 -------------------------------------------------------------------------------- /img/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/__init__.py -------------------------------------------------------------------------------- /img/icons/app_modify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/app_modify.png -------------------------------------------------------------------------------- /img/icons/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/arrow_down.png -------------------------------------------------------------------------------- /img/icons/calendar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/calendar.png -------------------------------------------------------------------------------- /img/icons/camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/camera.png -------------------------------------------------------------------------------- /img/icons/cancel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/cancel.png -------------------------------------------------------------------------------- /img/icons/cancel2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/cancel2.png -------------------------------------------------------------------------------- /img/icons/check.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/check.png -------------------------------------------------------------------------------- /img/icons/check_inbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/check_inbox.png -------------------------------------------------------------------------------- /img/icons/check_tasks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/check_tasks.png -------------------------------------------------------------------------------- /img/icons/checks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/checks.png -------------------------------------------------------------------------------- /img/icons/code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/code.png -------------------------------------------------------------------------------- /img/icons/customize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/customize.png -------------------------------------------------------------------------------- /img/icons/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/default.png -------------------------------------------------------------------------------- /img/icons/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/download.png -------------------------------------------------------------------------------- /img/icons/download1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/download1.png -------------------------------------------------------------------------------- /img/icons/email.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/email.png -------------------------------------------------------------------------------- /img/icons/email_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/email_yellow.png -------------------------------------------------------------------------------- /img/icons/file_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_add.png -------------------------------------------------------------------------------- /img/icons/file_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_code.png -------------------------------------------------------------------------------- /img/icons/file_delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_delete.png -------------------------------------------------------------------------------- /img/icons/file_image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_image.png -------------------------------------------------------------------------------- /img/icons/file_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_load.png -------------------------------------------------------------------------------- /img/icons/file_modify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_modify.png -------------------------------------------------------------------------------- /img/icons/file_move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_move.png -------------------------------------------------------------------------------- /img/icons/file_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_open.png -------------------------------------------------------------------------------- /img/icons/file_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/file_play.png -------------------------------------------------------------------------------- /img/icons/folder_closed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/folder_closed.png -------------------------------------------------------------------------------- /img/icons/folder_content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/folder_content.png -------------------------------------------------------------------------------- /img/icons/folder_open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/folder_open.png -------------------------------------------------------------------------------- /img/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/help.png -------------------------------------------------------------------------------- /img/icons/help2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/help2.png -------------------------------------------------------------------------------- /img/icons/load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/load.png -------------------------------------------------------------------------------- /img/icons/load2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/load2.png -------------------------------------------------------------------------------- /img/icons/load_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/load_yellow.png -------------------------------------------------------------------------------- /img/icons/minus1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/minus1.png -------------------------------------------------------------------------------- /img/icons/minus2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/minus2.png -------------------------------------------------------------------------------- /img/icons/minus3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/minus3.png -------------------------------------------------------------------------------- /img/icons/minus4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/minus4.png -------------------------------------------------------------------------------- /img/icons/notification.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/notification.png -------------------------------------------------------------------------------- /img/icons/notification_new.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/notification_new.png -------------------------------------------------------------------------------- /img/icons/p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/p.png -------------------------------------------------------------------------------- /img/icons/p_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/p_yellow.png -------------------------------------------------------------------------------- /img/icons/pen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/pen.png -------------------------------------------------------------------------------- /img/icons/pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/pipeline.png -------------------------------------------------------------------------------- /img/icons/plus1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/plus1.png -------------------------------------------------------------------------------- /img/icons/plus2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/plus2.png -------------------------------------------------------------------------------- /img/icons/plus3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/plus3.png -------------------------------------------------------------------------------- /img/icons/plus4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/plus4.png -------------------------------------------------------------------------------- /img/icons/project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/project.png -------------------------------------------------------------------------------- /img/icons/project2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/project2.png -------------------------------------------------------------------------------- /img/icons/save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/save.png -------------------------------------------------------------------------------- /img/icons/save2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/save2.png -------------------------------------------------------------------------------- /img/icons/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/settings.png -------------------------------------------------------------------------------- /img/icons/software.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/software.png -------------------------------------------------------------------------------- /img/icons/update.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/update.png -------------------------------------------------------------------------------- /img/icons/update_screen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/update_screen.png -------------------------------------------------------------------------------- /img/icons/upload_cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/upload_cloud.png -------------------------------------------------------------------------------- /img/icons/user_modify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/icons/user_modify.png -------------------------------------------------------------------------------- /img/labels/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/labels/default.png -------------------------------------------------------------------------------- /img/labels/shader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/labels/shader.png -------------------------------------------------------------------------------- /img/labels/shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/labels/shot.png -------------------------------------------------------------------------------- /img/menu/separator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/separator.png -------------------------------------------------------------------------------- /img/menu/shelf_atools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_atools.png -------------------------------------------------------------------------------- /img/menu/shelf_attach_shader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_attach_shader.png -------------------------------------------------------------------------------- /img/menu/shelf_camera.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_camera.png -------------------------------------------------------------------------------- /img/menu/shelf_creation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_creation.png -------------------------------------------------------------------------------- /img/menu/shelf_default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_default.png -------------------------------------------------------------------------------- /img/menu/shelf_graph_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_graph_editor.png -------------------------------------------------------------------------------- /img/menu/shelf_help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_help.png -------------------------------------------------------------------------------- /img/menu/shelf_hypershade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_hypershade.png -------------------------------------------------------------------------------- /img/menu/shelf_light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_light.png -------------------------------------------------------------------------------- /img/menu/shelf_light_linker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_light_linker.png -------------------------------------------------------------------------------- /img/menu/shelf_load.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_load.png -------------------------------------------------------------------------------- /img/menu/shelf_name.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_name.png -------------------------------------------------------------------------------- /img/menu/shelf_node_editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_node_editor.png -------------------------------------------------------------------------------- /img/menu/shelf_open_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_open_folder.png -------------------------------------------------------------------------------- /img/menu/shelf_open_folder_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_open_folder_project.png -------------------------------------------------------------------------------- /img/menu/shelf_outliner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_outliner.png -------------------------------------------------------------------------------- /img/menu/shelf_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_play.png -------------------------------------------------------------------------------- /img/menu/shelf_playblast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_playblast.png -------------------------------------------------------------------------------- /img/menu/shelf_publish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_publish.png -------------------------------------------------------------------------------- /img/menu/shelf_refresh_pipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_refresh_pipe.png -------------------------------------------------------------------------------- /img/menu/shelf_rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_rename.png -------------------------------------------------------------------------------- /img/menu/shelf_render.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_render.png -------------------------------------------------------------------------------- /img/menu/shelf_render_deliver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_render_deliver.png -------------------------------------------------------------------------------- /img/menu/shelf_render_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_render_preview.png -------------------------------------------------------------------------------- /img/menu/shelf_render_work.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_render_work.png -------------------------------------------------------------------------------- /img/menu/shelf_renderthreads.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_renderthreads.png -------------------------------------------------------------------------------- /img/menu/shelf_report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_report.png -------------------------------------------------------------------------------- /img/menu/shelf_save.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_save.png -------------------------------------------------------------------------------- /img/menu/shelf_snap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_snap.png -------------------------------------------------------------------------------- /img/menu/shelf_switch_abc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_switch_abc.png -------------------------------------------------------------------------------- /img/menu/shelf_switch_ass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_switch_ass.png -------------------------------------------------------------------------------- /img/menu/shelf_switch_box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_switch_box.png -------------------------------------------------------------------------------- /img/menu/shelf_switch_gpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_switch_gpu.png -------------------------------------------------------------------------------- /img/menu/shelf_switch_loc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_switch_loc.png -------------------------------------------------------------------------------- /img/menu/shelf_switch_ma.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_switch_ma.png -------------------------------------------------------------------------------- /img/menu/shelf_viewport.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/menu/shelf_viewport.png -------------------------------------------------------------------------------- /img/software/default/3dCoat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/3dCoat.png -------------------------------------------------------------------------------- /img/software/default/CPlusPlus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/CPlusPlus.png -------------------------------------------------------------------------------- /img/software/default/afterEffects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/afterEffects.png -------------------------------------------------------------------------------- /img/software/default/alembic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/alembic.png -------------------------------------------------------------------------------- /img/software/default/arnold.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/arnold.png -------------------------------------------------------------------------------- /img/software/default/blender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/blender.png -------------------------------------------------------------------------------- /img/software/default/bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/bridge.png -------------------------------------------------------------------------------- /img/software/default/cinema4d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/cinema4d.png -------------------------------------------------------------------------------- /img/software/default/csharp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/csharp.png -------------------------------------------------------------------------------- /img/software/default/davinci.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/davinci.png -------------------------------------------------------------------------------- /img/software/default/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/default.png -------------------------------------------------------------------------------- /img/software/default/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/folder.png -------------------------------------------------------------------------------- /img/software/default/houdini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/houdini.png -------------------------------------------------------------------------------- /img/software/default/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/img.png -------------------------------------------------------------------------------- /img/software/default/katana.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/katana.png -------------------------------------------------------------------------------- /img/software/default/mari.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/mari.png -------------------------------------------------------------------------------- /img/software/default/max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/max.png -------------------------------------------------------------------------------- /img/software/default/maxScript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/maxScript.png -------------------------------------------------------------------------------- /img/software/default/maya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/maya.png -------------------------------------------------------------------------------- /img/software/default/mel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/mel.png -------------------------------------------------------------------------------- /img/software/default/mentalray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/mentalray.png -------------------------------------------------------------------------------- /img/software/default/modo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/modo.png -------------------------------------------------------------------------------- /img/software/default/motionbuilder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/motionbuilder.png -------------------------------------------------------------------------------- /img/software/default/motive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/motive.png -------------------------------------------------------------------------------- /img/software/default/nuke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/nuke.png -------------------------------------------------------------------------------- /img/software/default/pdf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/pdf.png -------------------------------------------------------------------------------- /img/software/default/pftrack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/pftrack.png -------------------------------------------------------------------------------- /img/software/default/photoscan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/photoscan.png -------------------------------------------------------------------------------- /img/software/default/photoshop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/photoshop.png -------------------------------------------------------------------------------- /img/software/default/premiere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/premiere.png -------------------------------------------------------------------------------- /img/software/default/ptex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/ptex.png -------------------------------------------------------------------------------- /img/software/default/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/python.png -------------------------------------------------------------------------------- /img/software/default/pythonBG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/pythonBG.png -------------------------------------------------------------------------------- /img/software/default/qt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/qt.png -------------------------------------------------------------------------------- /img/software/default/quicktimeplayer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/quicktimeplayer.png -------------------------------------------------------------------------------- /img/software/default/redshift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/redshift.png -------------------------------------------------------------------------------- /img/software/default/renderman.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/renderman.png -------------------------------------------------------------------------------- /img/software/default/rv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/rv.png -------------------------------------------------------------------------------- /img/software/default/unity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/unity.png -------------------------------------------------------------------------------- /img/software/default/vlc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/vlc.png -------------------------------------------------------------------------------- /img/software/default/vray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/vray.png -------------------------------------------------------------------------------- /img/software/default/yeti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/yeti.png -------------------------------------------------------------------------------- /img/software/default/zbrush.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/default/zbrush.png -------------------------------------------------------------------------------- /img/software/houdini/houdini.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/houdini/houdini.ico -------------------------------------------------------------------------------- /img/software/houdini/houdini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/houdini/houdini.png -------------------------------------------------------------------------------- /img/software/houdini/houdini_splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/houdini/houdini_splash.png -------------------------------------------------------------------------------- /img/software/max/max.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/max/max.ico -------------------------------------------------------------------------------- /img/software/max/max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/max/max.png -------------------------------------------------------------------------------- /img/software/max/splash.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/max/splash.bmp -------------------------------------------------------------------------------- /img/software/maya/MayaEDUStartupImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/maya/MayaEDUStartupImage.png -------------------------------------------------------------------------------- /img/software/maya/MayaStartupImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/maya/MayaStartupImage.png -------------------------------------------------------------------------------- /img/software/maya/maya.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/maya/maya.ico -------------------------------------------------------------------------------- /img/software/maya/maya.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/maya/maya.png -------------------------------------------------------------------------------- /img/software/nuke/menu/help.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/help.ico -------------------------------------------------------------------------------- /img/software/nuke/menu/load.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/load.ico -------------------------------------------------------------------------------- /img/software/nuke/menu/nuke_toolbar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/nuke_toolbar.png -------------------------------------------------------------------------------- /img/software/nuke/menu/report.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/report.ico -------------------------------------------------------------------------------- /img/software/nuke/menu/save.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/save.ico -------------------------------------------------------------------------------- /img/software/nuke/menu/write.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/write.ico -------------------------------------------------------------------------------- /img/software/nuke/menu/writeBanner52.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/menu/writeBanner52.png -------------------------------------------------------------------------------- /img/software/nuke/nuke.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/nuke.ico -------------------------------------------------------------------------------- /img/software/nuke/nuke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/software/nuke/nuke.png -------------------------------------------------------------------------------- /img/user/alexa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/user/alexa.png -------------------------------------------------------------------------------- /img/user/arichter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/user/arichter.png -------------------------------------------------------------------------------- /img/user/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/img/user/default.png -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- 1 | import dcc, utils 2 | -------------------------------------------------------------------------------- /scripts/extern/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/scripts/extern/__init__.py -------------------------------------------------------------------------------- /scripts/extern/yaml/composer.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['Composer', 'ComposerError'] 3 | 4 | from .error import MarkedYAMLError 5 | from .events import * 6 | from .nodes import * 7 | 8 | class ComposerError(MarkedYAMLError): 9 | pass 10 | 11 | class Composer: 12 | 13 | def __init__(self): 14 | self.anchors = {} 15 | 16 | def check_node(self): 17 | # Drop the STREAM-START event. 18 | if self.check_event(StreamStartEvent): 19 | self.get_event() 20 | 21 | # If there are more documents available? 22 | return not self.check_event(StreamEndEvent) 23 | 24 | def get_node(self): 25 | # Get the root node of the next document. 26 | if not self.check_event(StreamEndEvent): 27 | return self.compose_document() 28 | 29 | def get_single_node(self): 30 | # Drop the STREAM-START event. 31 | self.get_event() 32 | 33 | # Compose a document if the stream is not empty. 34 | document = None 35 | if not self.check_event(StreamEndEvent): 36 | document = self.compose_document() 37 | 38 | # Ensure that the stream contains no more documents. 39 | if not self.check_event(StreamEndEvent): 40 | event = self.get_event() 41 | raise ComposerError("expected a single document in the stream", 42 | document.start_mark, "but found another document", 43 | event.start_mark) 44 | 45 | # Drop the STREAM-END event. 46 | self.get_event() 47 | 48 | return document 49 | 50 | def compose_document(self): 51 | # Drop the DOCUMENT-START event. 52 | self.get_event() 53 | 54 | # Compose the root node. 55 | node = self.compose_node(None, None) 56 | 57 | # Drop the DOCUMENT-END event. 58 | self.get_event() 59 | 60 | self.anchors = {} 61 | return node 62 | 63 | def compose_node(self, parent, index): 64 | if self.check_event(AliasEvent): 65 | event = self.get_event() 66 | anchor = event.anchor 67 | if anchor not in self.anchors: 68 | raise ComposerError(None, None, "found undefined alias %r" 69 | % anchor, event.start_mark) 70 | return self.anchors[anchor] 71 | event = self.peek_event() 72 | anchor = event.anchor 73 | if anchor is not None: 74 | if anchor in self.anchors: 75 | raise ComposerError("found duplicate anchor %r; first occurrence" 76 | % anchor, self.anchors[anchor].start_mark, 77 | "second occurrence", event.start_mark) 78 | self.descend_resolver(parent, index) 79 | if self.check_event(ScalarEvent): 80 | node = self.compose_scalar_node(anchor) 81 | elif self.check_event(SequenceStartEvent): 82 | node = self.compose_sequence_node(anchor) 83 | elif self.check_event(MappingStartEvent): 84 | node = self.compose_mapping_node(anchor) 85 | self.ascend_resolver() 86 | return node 87 | 88 | def compose_scalar_node(self, anchor): 89 | event = self.get_event() 90 | tag = event.tag 91 | if tag is None or tag == '!': 92 | tag = self.resolve(ScalarNode, event.value, event.implicit) 93 | node = ScalarNode(tag, event.value, 94 | event.start_mark, event.end_mark, style=event.style) 95 | if anchor is not None: 96 | self.anchors[anchor] = node 97 | return node 98 | 99 | def compose_sequence_node(self, anchor): 100 | start_event = self.get_event() 101 | tag = start_event.tag 102 | if tag is None or tag == '!': 103 | tag = self.resolve(SequenceNode, None, start_event.implicit) 104 | node = SequenceNode(tag, [], 105 | start_event.start_mark, None, 106 | flow_style=start_event.flow_style) 107 | if anchor is not None: 108 | self.anchors[anchor] = node 109 | index = 0 110 | while not self.check_event(SequenceEndEvent): 111 | node.value.append(self.compose_node(node, index)) 112 | index += 1 113 | end_event = self.get_event() 114 | node.end_mark = end_event.end_mark 115 | return node 116 | 117 | def compose_mapping_node(self, anchor): 118 | start_event = self.get_event() 119 | tag = start_event.tag 120 | if tag is None or tag == '!': 121 | tag = self.resolve(MappingNode, None, start_event.implicit) 122 | node = MappingNode(tag, [], 123 | start_event.start_mark, None, 124 | flow_style=start_event.flow_style) 125 | if anchor is not None: 126 | self.anchors[anchor] = node 127 | while not self.check_event(MappingEndEvent): 128 | #key_event = self.peek_event() 129 | item_key = self.compose_node(node, None) 130 | #if item_key in node.value: 131 | # raise ComposerError("while composing a mapping", start_event.start_mark, 132 | # "found duplicate key", key_event.start_mark) 133 | item_value = self.compose_node(node, item_key) 134 | #node.value[item_key] = item_value 135 | node.value.append((item_key, item_value)) 136 | end_event = self.get_event() 137 | node.end_mark = end_event.end_mark 138 | return node 139 | 140 | -------------------------------------------------------------------------------- /scripts/extern/yaml/cyaml.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = [ 3 | 'CBaseLoader', 'CSafeLoader', 'CFullLoader', 'CUnsafeLoader', 'CLoader', 4 | 'CBaseDumper', 'CSafeDumper', 'CDumper' 5 | ] 6 | 7 | from yaml._yaml import CParser, CEmitter 8 | 9 | from .constructor import * 10 | 11 | from .serializer import * 12 | from .representer import * 13 | 14 | from .resolver import * 15 | 16 | class CBaseLoader(CParser, BaseConstructor, BaseResolver): 17 | 18 | def __init__(self, stream): 19 | CParser.__init__(self, stream) 20 | BaseConstructor.__init__(self) 21 | BaseResolver.__init__(self) 22 | 23 | class CSafeLoader(CParser, SafeConstructor, Resolver): 24 | 25 | def __init__(self, stream): 26 | CParser.__init__(self, stream) 27 | SafeConstructor.__init__(self) 28 | Resolver.__init__(self) 29 | 30 | class CFullLoader(CParser, FullConstructor, Resolver): 31 | 32 | def __init__(self, stream): 33 | CParser.__init__(self, stream) 34 | FullConstructor.__init__(self) 35 | Resolver.__init__(self) 36 | 37 | class CUnsafeLoader(CParser, UnsafeConstructor, Resolver): 38 | 39 | def __init__(self, stream): 40 | CParser.__init__(self, stream) 41 | UnsafeConstructor.__init__(self) 42 | Resolver.__init__(self) 43 | 44 | class CLoader(CParser, Constructor, Resolver): 45 | 46 | def __init__(self, stream): 47 | CParser.__init__(self, stream) 48 | Constructor.__init__(self) 49 | Resolver.__init__(self) 50 | 51 | class CBaseDumper(CEmitter, BaseRepresenter, BaseResolver): 52 | 53 | def __init__(self, stream, 54 | default_style=None, default_flow_style=False, 55 | canonical=None, indent=None, width=None, 56 | allow_unicode=None, line_break=None, 57 | encoding=None, explicit_start=None, explicit_end=None, 58 | version=None, tags=None, sort_keys=True): 59 | CEmitter.__init__(self, stream, canonical=canonical, 60 | indent=indent, width=width, encoding=encoding, 61 | allow_unicode=allow_unicode, line_break=line_break, 62 | explicit_start=explicit_start, explicit_end=explicit_end, 63 | version=version, tags=tags) 64 | Representer.__init__(self, default_style=default_style, 65 | default_flow_style=default_flow_style, sort_keys=sort_keys) 66 | Resolver.__init__(self) 67 | 68 | class CSafeDumper(CEmitter, SafeRepresenter, Resolver): 69 | 70 | def __init__(self, stream, 71 | default_style=None, default_flow_style=False, 72 | canonical=None, indent=None, width=None, 73 | allow_unicode=None, line_break=None, 74 | encoding=None, explicit_start=None, explicit_end=None, 75 | version=None, tags=None, sort_keys=True): 76 | CEmitter.__init__(self, stream, canonical=canonical, 77 | indent=indent, width=width, encoding=encoding, 78 | allow_unicode=allow_unicode, line_break=line_break, 79 | explicit_start=explicit_start, explicit_end=explicit_end, 80 | version=version, tags=tags) 81 | SafeRepresenter.__init__(self, default_style=default_style, 82 | default_flow_style=default_flow_style, sort_keys=sort_keys) 83 | Resolver.__init__(self) 84 | 85 | class CDumper(CEmitter, Serializer, Representer, Resolver): 86 | 87 | def __init__(self, stream, 88 | default_style=None, default_flow_style=False, 89 | canonical=None, indent=None, width=None, 90 | allow_unicode=None, line_break=None, 91 | encoding=None, explicit_start=None, explicit_end=None, 92 | version=None, tags=None, sort_keys=True): 93 | CEmitter.__init__(self, stream, canonical=canonical, 94 | indent=indent, width=width, encoding=encoding, 95 | allow_unicode=allow_unicode, line_break=line_break, 96 | explicit_start=explicit_start, explicit_end=explicit_end, 97 | version=version, tags=tags) 98 | Representer.__init__(self, default_style=default_style, 99 | default_flow_style=default_flow_style, sort_keys=sort_keys) 100 | Resolver.__init__(self) 101 | 102 | -------------------------------------------------------------------------------- /scripts/extern/yaml/dumper.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['BaseDumper', 'SafeDumper', 'Dumper'] 3 | 4 | from .emitter import * 5 | from .serializer import * 6 | from .representer import * 7 | from .resolver import * 8 | 9 | class BaseDumper(Emitter, Serializer, BaseRepresenter, BaseResolver): 10 | 11 | def __init__(self, stream, 12 | default_style=None, default_flow_style=False, 13 | canonical=None, indent=None, width=None, 14 | allow_unicode=None, line_break=None, 15 | encoding=None, explicit_start=None, explicit_end=None, 16 | version=None, tags=None, sort_keys=True): 17 | Emitter.__init__(self, stream, canonical=canonical, 18 | indent=indent, width=width, 19 | allow_unicode=allow_unicode, line_break=line_break) 20 | Serializer.__init__(self, encoding=encoding, 21 | explicit_start=explicit_start, explicit_end=explicit_end, 22 | version=version, tags=tags) 23 | Representer.__init__(self, default_style=default_style, 24 | default_flow_style=default_flow_style, sort_keys=sort_keys) 25 | Resolver.__init__(self) 26 | 27 | class SafeDumper(Emitter, Serializer, SafeRepresenter, Resolver): 28 | 29 | def __init__(self, stream, 30 | default_style=None, default_flow_style=False, 31 | canonical=None, indent=None, width=None, 32 | allow_unicode=None, line_break=None, 33 | encoding=None, explicit_start=None, explicit_end=None, 34 | version=None, tags=None, sort_keys=True): 35 | Emitter.__init__(self, stream, canonical=canonical, 36 | indent=indent, width=width, 37 | allow_unicode=allow_unicode, line_break=line_break) 38 | Serializer.__init__(self, encoding=encoding, 39 | explicit_start=explicit_start, explicit_end=explicit_end, 40 | version=version, tags=tags) 41 | SafeRepresenter.__init__(self, default_style=default_style, 42 | default_flow_style=default_flow_style, sort_keys=sort_keys) 43 | Resolver.__init__(self) 44 | 45 | class Dumper(Emitter, Serializer, Representer, Resolver): 46 | 47 | def __init__(self, stream, 48 | default_style=None, default_flow_style=False, 49 | canonical=None, indent=None, width=None, 50 | allow_unicode=None, line_break=None, 51 | encoding=None, explicit_start=None, explicit_end=None, 52 | version=None, tags=None, sort_keys=True): 53 | Emitter.__init__(self, stream, canonical=canonical, 54 | indent=indent, width=width, 55 | allow_unicode=allow_unicode, line_break=line_break) 56 | Serializer.__init__(self, encoding=encoding, 57 | explicit_start=explicit_start, explicit_end=explicit_end, 58 | version=version, tags=tags) 59 | Representer.__init__(self, default_style=default_style, 60 | default_flow_style=default_flow_style, sort_keys=sort_keys) 61 | Resolver.__init__(self) 62 | 63 | -------------------------------------------------------------------------------- /scripts/extern/yaml/error.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['Mark', 'YAMLError', 'MarkedYAMLError'] 3 | 4 | class Mark: 5 | 6 | def __init__(self, name, index, line, column, buffer, pointer): 7 | self.name = name 8 | self.index = index 9 | self.line = line 10 | self.column = column 11 | self.buffer = buffer 12 | self.pointer = pointer 13 | 14 | def get_snippet(self, indent=4, max_length=75): 15 | if self.buffer is None: 16 | return None 17 | head = '' 18 | start = self.pointer 19 | while start > 0 and self.buffer[start-1] not in '\0\r\n\x85\u2028\u2029': 20 | start -= 1 21 | if self.pointer-start > max_length/2-1: 22 | head = ' ... ' 23 | start += 5 24 | break 25 | tail = '' 26 | end = self.pointer 27 | while end < len(self.buffer) and self.buffer[end] not in '\0\r\n\x85\u2028\u2029': 28 | end += 1 29 | if end-self.pointer > max_length/2-1: 30 | tail = ' ... ' 31 | end -= 5 32 | break 33 | snippet = self.buffer[start:end] 34 | return ' '*indent + head + snippet + tail + '\n' \ 35 | + ' '*(indent+self.pointer-start+len(head)) + '^' 36 | 37 | def __str__(self): 38 | snippet = self.get_snippet() 39 | where = " in \"%s\", line %d, column %d" \ 40 | % (self.name, self.line+1, self.column+1) 41 | if snippet is not None: 42 | where += ":\n"+snippet 43 | return where 44 | 45 | class YAMLError(Exception): 46 | pass 47 | 48 | class MarkedYAMLError(YAMLError): 49 | 50 | def __init__(self, context=None, context_mark=None, 51 | problem=None, problem_mark=None, note=None): 52 | self.context = context 53 | self.context_mark = context_mark 54 | self.problem = problem 55 | self.problem_mark = problem_mark 56 | self.note = note 57 | 58 | def __str__(self): 59 | lines = [] 60 | if self.context is not None: 61 | lines.append(self.context) 62 | if self.context_mark is not None \ 63 | and (self.problem is None or self.problem_mark is None 64 | or self.context_mark.name != self.problem_mark.name 65 | or self.context_mark.line != self.problem_mark.line 66 | or self.context_mark.column != self.problem_mark.column): 67 | lines.append(str(self.context_mark)) 68 | if self.problem is not None: 69 | lines.append(self.problem) 70 | if self.problem_mark is not None: 71 | lines.append(str(self.problem_mark)) 72 | if self.note is not None: 73 | lines.append(self.note) 74 | return '\n'.join(lines) 75 | 76 | -------------------------------------------------------------------------------- /scripts/extern/yaml/events.py: -------------------------------------------------------------------------------- 1 | 2 | # Abstract classes. 3 | 4 | class Event(object): 5 | def __init__(self, start_mark=None, end_mark=None): 6 | self.start_mark = start_mark 7 | self.end_mark = end_mark 8 | def __repr__(self): 9 | attributes = [key for key in ['anchor', 'tag', 'implicit', 'value'] 10 | if hasattr(self, key)] 11 | arguments = ', '.join(['%s=%r' % (key, getattr(self, key)) 12 | for key in attributes]) 13 | return '%s(%s)' % (self.__class__.__name__, arguments) 14 | 15 | class NodeEvent(Event): 16 | def __init__(self, anchor, start_mark=None, end_mark=None): 17 | self.anchor = anchor 18 | self.start_mark = start_mark 19 | self.end_mark = end_mark 20 | 21 | class CollectionStartEvent(NodeEvent): 22 | def __init__(self, anchor, tag, implicit, start_mark=None, end_mark=None, 23 | flow_style=None): 24 | self.anchor = anchor 25 | self.tag = tag 26 | self.implicit = implicit 27 | self.start_mark = start_mark 28 | self.end_mark = end_mark 29 | self.flow_style = flow_style 30 | 31 | class CollectionEndEvent(Event): 32 | pass 33 | 34 | # Implementations. 35 | 36 | class StreamStartEvent(Event): 37 | def __init__(self, start_mark=None, end_mark=None, encoding=None): 38 | self.start_mark = start_mark 39 | self.end_mark = end_mark 40 | self.encoding = encoding 41 | 42 | class StreamEndEvent(Event): 43 | pass 44 | 45 | class DocumentStartEvent(Event): 46 | def __init__(self, start_mark=None, end_mark=None, 47 | explicit=None, version=None, tags=None): 48 | self.start_mark = start_mark 49 | self.end_mark = end_mark 50 | self.explicit = explicit 51 | self.version = version 52 | self.tags = tags 53 | 54 | class DocumentEndEvent(Event): 55 | def __init__(self, start_mark=None, end_mark=None, 56 | explicit=None): 57 | self.start_mark = start_mark 58 | self.end_mark = end_mark 59 | self.explicit = explicit 60 | 61 | class AliasEvent(NodeEvent): 62 | pass 63 | 64 | class ScalarEvent(NodeEvent): 65 | def __init__(self, anchor, tag, implicit, value, 66 | start_mark=None, end_mark=None, style=None): 67 | self.anchor = anchor 68 | self.tag = tag 69 | self.implicit = implicit 70 | self.value = value 71 | self.start_mark = start_mark 72 | self.end_mark = end_mark 73 | self.style = style 74 | 75 | class SequenceStartEvent(CollectionStartEvent): 76 | pass 77 | 78 | class SequenceEndEvent(CollectionEndEvent): 79 | pass 80 | 81 | class MappingStartEvent(CollectionStartEvent): 82 | pass 83 | 84 | class MappingEndEvent(CollectionEndEvent): 85 | pass 86 | 87 | -------------------------------------------------------------------------------- /scripts/extern/yaml/loader.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['BaseLoader', 'FullLoader', 'SafeLoader', 'Loader', 'UnsafeLoader'] 3 | 4 | from .reader import * 5 | from .scanner import * 6 | from .parser import * 7 | from .composer import * 8 | from .constructor import * 9 | from .resolver import * 10 | 11 | class BaseLoader(Reader, Scanner, Parser, Composer, BaseConstructor, BaseResolver): 12 | 13 | def __init__(self, stream): 14 | Reader.__init__(self, stream) 15 | Scanner.__init__(self) 16 | Parser.__init__(self) 17 | Composer.__init__(self) 18 | BaseConstructor.__init__(self) 19 | BaseResolver.__init__(self) 20 | 21 | class FullLoader(Reader, Scanner, Parser, Composer, FullConstructor, Resolver): 22 | 23 | def __init__(self, stream): 24 | Reader.__init__(self, stream) 25 | Scanner.__init__(self) 26 | Parser.__init__(self) 27 | Composer.__init__(self) 28 | FullConstructor.__init__(self) 29 | Resolver.__init__(self) 30 | 31 | class SafeLoader(Reader, Scanner, Parser, Composer, SafeConstructor, Resolver): 32 | 33 | def __init__(self, stream): 34 | Reader.__init__(self, stream) 35 | Scanner.__init__(self) 36 | Parser.__init__(self) 37 | Composer.__init__(self) 38 | SafeConstructor.__init__(self) 39 | Resolver.__init__(self) 40 | 41 | class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver): 42 | 43 | def __init__(self, stream): 44 | Reader.__init__(self, stream) 45 | Scanner.__init__(self) 46 | Parser.__init__(self) 47 | Composer.__init__(self) 48 | Constructor.__init__(self) 49 | Resolver.__init__(self) 50 | 51 | # UnsafeLoader is the same as Loader (which is and was always unsafe on 52 | # untrusted input). Use of either Loader or UnsafeLoader should be rare, since 53 | # FullLoad should be able to load almost all YAML safely. Loader is left intact 54 | # to ensure backwards compatibility. 55 | class UnsafeLoader(Reader, Scanner, Parser, Composer, Constructor, Resolver): 56 | 57 | def __init__(self, stream): 58 | Reader.__init__(self, stream) 59 | Scanner.__init__(self) 60 | Parser.__init__(self) 61 | Composer.__init__(self) 62 | Constructor.__init__(self) 63 | Resolver.__init__(self) 64 | -------------------------------------------------------------------------------- /scripts/extern/yaml/nodes.py: -------------------------------------------------------------------------------- 1 | 2 | class Node(object): 3 | def __init__(self, tag, value, start_mark, end_mark): 4 | self.tag = tag 5 | self.value = value 6 | self.start_mark = start_mark 7 | self.end_mark = end_mark 8 | def __repr__(self): 9 | value = self.value 10 | #if isinstance(value, list): 11 | # if len(value) == 0: 12 | # value = '' 13 | # elif len(value) == 1: 14 | # value = '<1 item>' 15 | # else: 16 | # value = '<%d items>' % len(value) 17 | #else: 18 | # if len(value) > 75: 19 | # value = repr(value[:70]+u' ... ') 20 | # else: 21 | # value = repr(value) 22 | value = repr(value) 23 | return '%s(tag=%r, value=%s)' % (self.__class__.__name__, self.tag, value) 24 | 25 | class ScalarNode(Node): 26 | id = 'scalar' 27 | def __init__(self, tag, value, 28 | start_mark=None, end_mark=None, style=None): 29 | self.tag = tag 30 | self.value = value 31 | self.start_mark = start_mark 32 | self.end_mark = end_mark 33 | self.style = style 34 | 35 | class CollectionNode(Node): 36 | def __init__(self, tag, value, 37 | start_mark=None, end_mark=None, flow_style=None): 38 | self.tag = tag 39 | self.value = value 40 | self.start_mark = start_mark 41 | self.end_mark = end_mark 42 | self.flow_style = flow_style 43 | 44 | class SequenceNode(CollectionNode): 45 | id = 'sequence' 46 | 47 | class MappingNode(CollectionNode): 48 | id = 'mapping' 49 | 50 | -------------------------------------------------------------------------------- /scripts/extern/yaml/reader.py: -------------------------------------------------------------------------------- 1 | # This module contains abstractions for the input stream. You don't have to 2 | # looks further, there are no pretty code. 3 | # 4 | # We define two classes here. 5 | # 6 | # Mark(source, line, column) 7 | # It's just a record and its only use is producing nice error messages. 8 | # Parser does not use it for any other purposes. 9 | # 10 | # Reader(source, data) 11 | # Reader determines the encoding of `data` and converts it to unicode. 12 | # Reader provides the following methods and attributes: 13 | # reader.peek(length=1) - return the next `length` characters 14 | # reader.forward(length=1) - move the current position to `length` characters. 15 | # reader.index - the number of the current character. 16 | # reader.line, stream.column - the line and the column of the current character. 17 | 18 | __all__ = ['Reader', 'ReaderError'] 19 | 20 | from .error import YAMLError, Mark 21 | 22 | import codecs, re 23 | 24 | class ReaderError(YAMLError): 25 | 26 | def __init__(self, name, position, character, encoding, reason): 27 | self.name = name 28 | self.character = character 29 | self.position = position 30 | self.encoding = encoding 31 | self.reason = reason 32 | 33 | def __str__(self): 34 | if isinstance(self.character, bytes): 35 | return "'%s' codec can't decode byte #x%02x: %s\n" \ 36 | " in \"%s\", position %d" \ 37 | % (self.encoding, ord(self.character), self.reason, 38 | self.name, self.position) 39 | else: 40 | return "unacceptable character #x%04x: %s\n" \ 41 | " in \"%s\", position %d" \ 42 | % (self.character, self.reason, 43 | self.name, self.position) 44 | 45 | class Reader(object): 46 | # Reader: 47 | # - determines the data encoding and converts it to a unicode string, 48 | # - checks if characters are in allowed range, 49 | # - adds '\0' to the end. 50 | 51 | # Reader accepts 52 | # - a `bytes` object, 53 | # - a `str` object, 54 | # - a file-like object with its `read` method returning `str`, 55 | # - a file-like object with its `read` method returning `unicode`. 56 | 57 | # Yeah, it's ugly and slow. 58 | 59 | def __init__(self, stream): 60 | self.name = None 61 | self.stream = None 62 | self.stream_pointer = 0 63 | self.eof = True 64 | self.buffer = '' 65 | self.pointer = 0 66 | self.raw_buffer = None 67 | self.raw_decode = None 68 | self.encoding = None 69 | self.index = 0 70 | self.line = 0 71 | self.column = 0 72 | if isinstance(stream, str): 73 | self.name = "" 74 | self.check_printable(stream) 75 | self.buffer = stream+'\0' 76 | elif isinstance(stream, bytes): 77 | self.name = "" 78 | self.raw_buffer = stream 79 | self.determine_encoding() 80 | else: 81 | self.stream = stream 82 | self.name = getattr(stream, 'name', "") 83 | self.eof = False 84 | self.raw_buffer = None 85 | self.determine_encoding() 86 | 87 | def peek(self, index=0): 88 | try: 89 | return self.buffer[self.pointer+index] 90 | except IndexError: 91 | self.update(index+1) 92 | return self.buffer[self.pointer+index] 93 | 94 | def prefix(self, length=1): 95 | if self.pointer+length >= len(self.buffer): 96 | self.update(length) 97 | return self.buffer[self.pointer:self.pointer+length] 98 | 99 | def forward(self, length=1): 100 | if self.pointer+length+1 >= len(self.buffer): 101 | self.update(length+1) 102 | while length: 103 | ch = self.buffer[self.pointer] 104 | self.pointer += 1 105 | self.index += 1 106 | if ch in '\n\x85\u2028\u2029' \ 107 | or (ch == '\r' and self.buffer[self.pointer] != '\n'): 108 | self.line += 1 109 | self.column = 0 110 | elif ch != '\uFEFF': 111 | self.column += 1 112 | length -= 1 113 | 114 | def get_mark(self): 115 | if self.stream is None: 116 | return Mark(self.name, self.index, self.line, self.column, 117 | self.buffer, self.pointer) 118 | else: 119 | return Mark(self.name, self.index, self.line, self.column, 120 | None, None) 121 | 122 | def determine_encoding(self): 123 | while not self.eof and (self.raw_buffer is None or len(self.raw_buffer) < 2): 124 | self.update_raw() 125 | if isinstance(self.raw_buffer, bytes): 126 | if self.raw_buffer.startswith(codecs.BOM_UTF16_LE): 127 | self.raw_decode = codecs.utf_16_le_decode 128 | self.encoding = 'utf-16-le' 129 | elif self.raw_buffer.startswith(codecs.BOM_UTF16_BE): 130 | self.raw_decode = codecs.utf_16_be_decode 131 | self.encoding = 'utf-16-be' 132 | else: 133 | self.raw_decode = codecs.utf_8_decode 134 | self.encoding = 'utf-8' 135 | self.update(1) 136 | 137 | NON_PRINTABLE = re.compile('[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]') 138 | def check_printable(self, data): 139 | match = self.NON_PRINTABLE.search(data) 140 | if match: 141 | character = match.group() 142 | position = self.index+(len(self.buffer)-self.pointer)+match.start() 143 | raise ReaderError(self.name, position, ord(character), 144 | 'unicode', "special characters are not allowed") 145 | 146 | def update(self, length): 147 | if self.raw_buffer is None: 148 | return 149 | self.buffer = self.buffer[self.pointer:] 150 | self.pointer = 0 151 | while len(self.buffer) < length: 152 | if not self.eof: 153 | self.update_raw() 154 | if self.raw_decode is not None: 155 | try: 156 | data, converted = self.raw_decode(self.raw_buffer, 157 | 'strict', self.eof) 158 | except UnicodeDecodeError as exc: 159 | character = self.raw_buffer[exc.start] 160 | if self.stream is not None: 161 | position = self.stream_pointer-len(self.raw_buffer)+exc.start 162 | else: 163 | position = exc.start 164 | raise ReaderError(self.name, position, character, 165 | exc.encoding, exc.reason) 166 | else: 167 | data = self.raw_buffer 168 | converted = len(data) 169 | self.check_printable(data) 170 | self.buffer += data 171 | self.raw_buffer = self.raw_buffer[converted:] 172 | if self.eof: 173 | self.buffer += '\0' 174 | self.raw_buffer = None 175 | break 176 | 177 | def update_raw(self, size=4096): 178 | data = self.stream.read(size) 179 | if self.raw_buffer is None: 180 | self.raw_buffer = data 181 | else: 182 | self.raw_buffer += data 183 | self.stream_pointer += len(data) 184 | if not data: 185 | self.eof = True 186 | -------------------------------------------------------------------------------- /scripts/extern/yaml/serializer.py: -------------------------------------------------------------------------------- 1 | 2 | __all__ = ['Serializer', 'SerializerError'] 3 | 4 | from .error import YAMLError 5 | from .events import * 6 | from .nodes import * 7 | 8 | class SerializerError(YAMLError): 9 | pass 10 | 11 | class Serializer: 12 | 13 | ANCHOR_TEMPLATE = 'id%03d' 14 | 15 | def __init__(self, encoding=None, 16 | explicit_start=None, explicit_end=None, version=None, tags=None): 17 | self.use_encoding = encoding 18 | self.use_explicit_start = explicit_start 19 | self.use_explicit_end = explicit_end 20 | self.use_version = version 21 | self.use_tags = tags 22 | self.serialized_nodes = {} 23 | self.anchors = {} 24 | self.last_anchor_id = 0 25 | self.closed = None 26 | 27 | def open(self): 28 | if self.closed is None: 29 | self.emit(StreamStartEvent(encoding=self.use_encoding)) 30 | self.closed = False 31 | elif self.closed: 32 | raise SerializerError("serializer is closed") 33 | else: 34 | raise SerializerError("serializer is already opened") 35 | 36 | def close(self): 37 | if self.closed is None: 38 | raise SerializerError("serializer is not opened") 39 | elif not self.closed: 40 | self.emit(StreamEndEvent()) 41 | self.closed = True 42 | 43 | #def __del__(self): 44 | # self.close() 45 | 46 | def serialize(self, node): 47 | if self.closed is None: 48 | raise SerializerError("serializer is not opened") 49 | elif self.closed: 50 | raise SerializerError("serializer is closed") 51 | self.emit(DocumentStartEvent(explicit=self.use_explicit_start, 52 | version=self.use_version, tags=self.use_tags)) 53 | self.anchor_node(node) 54 | self.serialize_node(node, None, None) 55 | self.emit(DocumentEndEvent(explicit=self.use_explicit_end)) 56 | self.serialized_nodes = {} 57 | self.anchors = {} 58 | self.last_anchor_id = 0 59 | 60 | def anchor_node(self, node): 61 | if node in self.anchors: 62 | if self.anchors[node] is None: 63 | self.anchors[node] = self.generate_anchor(node) 64 | else: 65 | self.anchors[node] = None 66 | if isinstance(node, SequenceNode): 67 | for item in node.value: 68 | self.anchor_node(item) 69 | elif isinstance(node, MappingNode): 70 | for key, value in node.value: 71 | self.anchor_node(key) 72 | self.anchor_node(value) 73 | 74 | def generate_anchor(self, node): 75 | self.last_anchor_id += 1 76 | return self.ANCHOR_TEMPLATE % self.last_anchor_id 77 | 78 | def serialize_node(self, node, parent, index): 79 | alias = self.anchors[node] 80 | if node in self.serialized_nodes: 81 | self.emit(AliasEvent(alias)) 82 | else: 83 | self.serialized_nodes[node] = True 84 | self.descend_resolver(parent, index) 85 | if isinstance(node, ScalarNode): 86 | detected_tag = self.resolve(ScalarNode, node.value, (True, False)) 87 | default_tag = self.resolve(ScalarNode, node.value, (False, True)) 88 | implicit = (node.tag == detected_tag), (node.tag == default_tag) 89 | self.emit(ScalarEvent(alias, node.tag, implicit, node.value, 90 | style=node.style)) 91 | elif isinstance(node, SequenceNode): 92 | implicit = (node.tag 93 | == self.resolve(SequenceNode, node.value, True)) 94 | self.emit(SequenceStartEvent(alias, node.tag, implicit, 95 | flow_style=node.flow_style)) 96 | index = 0 97 | for item in node.value: 98 | self.serialize_node(item, node, index) 99 | index += 1 100 | self.emit(SequenceEndEvent()) 101 | elif isinstance(node, MappingNode): 102 | implicit = (node.tag 103 | == self.resolve(MappingNode, node.value, True)) 104 | self.emit(MappingStartEvent(alias, node.tag, implicit, 105 | flow_style=node.flow_style)) 106 | for key, value in node.value: 107 | self.serialize_node(key, node, None) 108 | self.serialize_node(value, node, key) 109 | self.emit(MappingEndEvent()) 110 | self.ascend_resolver() 111 | 112 | -------------------------------------------------------------------------------- /scripts/extern/yaml/tokens.py: -------------------------------------------------------------------------------- 1 | 2 | class Token(object): 3 | def __init__(self, start_mark, end_mark): 4 | self.start_mark = start_mark 5 | self.end_mark = end_mark 6 | def __repr__(self): 7 | attributes = [key for key in self.__dict__ 8 | if not key.endswith('_mark')] 9 | attributes.sort() 10 | arguments = ', '.join(['%s=%r' % (key, getattr(self, key)) 11 | for key in attributes]) 12 | return '%s(%s)' % (self.__class__.__name__, arguments) 13 | 14 | #class BOMToken(Token): 15 | # id = '' 16 | 17 | class DirectiveToken(Token): 18 | id = '' 19 | def __init__(self, name, value, start_mark, end_mark): 20 | self.name = name 21 | self.value = value 22 | self.start_mark = start_mark 23 | self.end_mark = end_mark 24 | 25 | class DocumentStartToken(Token): 26 | id = '' 27 | 28 | class DocumentEndToken(Token): 29 | id = '' 30 | 31 | class StreamStartToken(Token): 32 | id = '' 33 | def __init__(self, start_mark=None, end_mark=None, 34 | encoding=None): 35 | self.start_mark = start_mark 36 | self.end_mark = end_mark 37 | self.encoding = encoding 38 | 39 | class StreamEndToken(Token): 40 | id = '' 41 | 42 | class BlockSequenceStartToken(Token): 43 | id = '' 44 | 45 | class BlockMappingStartToken(Token): 46 | id = '' 47 | 48 | class BlockEndToken(Token): 49 | id = '' 50 | 51 | class FlowSequenceStartToken(Token): 52 | id = '[' 53 | 54 | class FlowMappingStartToken(Token): 55 | id = '{' 56 | 57 | class FlowSequenceEndToken(Token): 58 | id = ']' 59 | 60 | class FlowMappingEndToken(Token): 61 | id = '}' 62 | 63 | class KeyToken(Token): 64 | id = '?' 65 | 66 | class ValueToken(Token): 67 | id = ':' 68 | 69 | class BlockEntryToken(Token): 70 | id = '-' 71 | 72 | class FlowEntryToken(Token): 73 | id = ',' 74 | 75 | class AliasToken(Token): 76 | id = '' 77 | def __init__(self, value, start_mark, end_mark): 78 | self.value = value 79 | self.start_mark = start_mark 80 | self.end_mark = end_mark 81 | 82 | class AnchorToken(Token): 83 | id = '' 84 | def __init__(self, value, start_mark, end_mark): 85 | self.value = value 86 | self.start_mark = start_mark 87 | self.end_mark = end_mark 88 | 89 | class TagToken(Token): 90 | id = '' 91 | def __init__(self, value, start_mark, end_mark): 92 | self.value = value 93 | self.start_mark = start_mark 94 | self.end_mark = end_mark 95 | 96 | class ScalarToken(Token): 97 | id = '' 98 | def __init__(self, value, plain, start_mark, end_mark, style=None): 99 | self.value = value 100 | self.plain = plain 101 | self.start_mark = start_mark 102 | self.end_mark = end_mark 103 | self.style = style 104 | 105 | -------------------------------------------------------------------------------- /scripts/plex.py: -------------------------------------------------------------------------------- 1 | # content = main hub 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import sys 9 | import getpass 10 | import webbrowser 11 | 12 | import plexfunc 13 | 14 | 15 | class Plex(plexfunc.Singleton): 16 | 17 | def plugin(plugin_name): 18 | module = __import__(plugin_name) 19 | return getattr(module, plugin_name.title()) 20 | 21 | 22 | # SOFTWARE ************************************************************ 23 | @property 24 | def software(self): 25 | """ Get the current software object based on the environment variable. 26 | RETURN: software class e.g. maya_dcc.Maya() 27 | """ 28 | module_name = f"{self.software_name}_dcc" if self.software_name else 'software' 29 | class_name = self.software_name.title() or 'Software' 30 | 31 | try: 32 | module = __import__(module_name, fromlist=[class_name]) 33 | return getattr(module, class_name)() 34 | except ImportError: 35 | from software import Software 36 | return Software() 37 | 38 | @property 39 | def software_name(self): 40 | return self.context['software'] 41 | 42 | @property 43 | def log(self): 44 | import plexlog 45 | return plexlog.init 46 | 47 | @property 48 | def announcement(self): 49 | # announcement order: overwrite than plex or project 50 | return self.config['plex']['announcement'] if self.config['plex']['announcement'] else self.config['project']['announcement'] 51 | 52 | 53 | # CONFIG ************************************************************* 54 | @property 55 | def config(self): 56 | """Merge all config files into one dictionary 57 | RETURN: dict of all config files 58 | """ 59 | if 'PLEX_CONFIG' not in os.environ: 60 | return self.config_refresh() 61 | all_config = eval(os.environ['PLEX_CONFIG']) 62 | 63 | if all_config.get('software_name') != self.software_name: 64 | all_config['software'] = self.config_software 65 | all_config['software_name'] = self.software_name 66 | os.environ['PLEX_CONFIG'] = str(all_config) 67 | 68 | return all_config 69 | 70 | def config_refresh(self): 71 | all_config = { 72 | 'plex': self.get_config('plex'), 73 | 'project': self.get_config('project'), 74 | 'script': self.get_config('script'), 75 | 'meta': self.get_config('meta'), 76 | 'software': self.config_software if self.software_name else {}, 77 | 'software_name': self.software_name 78 | } 79 | os.environ['PLEX_CONFIG'] = str(all_config) 80 | return all_config 81 | 82 | @property 83 | def config_software(self): 84 | return self.get_config(f'software/{self.software_name}') 85 | 86 | 87 | # CONFIG: Get & Set ************************************************** 88 | def get_config(self, file_name='', file_dir=''): 89 | if not file_dir: 90 | file_dir = self.get_config_path(file_name) 91 | 92 | # Handle file name and extension 93 | base_name = os.path.splitext(file_name)[0] 94 | file_path = os.path.normpath(os.path.join(file_dir, f"{base_name}.yml")) 95 | 96 | if os.path.exists(file_path): 97 | return plexfunc.get_yaml_content(file_path, (self.paths | self.context)) 98 | 99 | print(f"CAN'T find file: {file_path}") 100 | return {} 101 | 102 | 103 | def set_config(self, path, key, value): 104 | if os.path.exists(path): 105 | tmp_content = plexfunc.get_yaml_content(path, self.paths) 106 | else: 107 | tmp_content = {} 108 | plexfunc.create_dir(path) 109 | 110 | tmp_content[key] = value 111 | plexfunc.set_yaml_content(path, tmp_content) 112 | 113 | 114 | def get_config_path(self, file_name='', full_path=False): 115 | """Get the correct config directory path without file extension""" 116 | if file_name == 'plex': 117 | file_dir = self.paths['config'] 118 | elif file_name == 'user': 119 | file_dir = self.paths['config_user'] 120 | else: 121 | file_dir = self.paths['config_project'] 122 | 123 | if full_path: 124 | return os.path.normpath(file_dir + file_name + '.yml') 125 | return os.path.normpath(file_dir) 126 | 127 | 128 | def get_img_path(self, end_path='btn/default'): 129 | img_format = '' if '.' in end_path else '.png' 130 | 131 | path = f'{self.paths["plex"]}/img/{end_path}{img_format}' or \ 132 | f'{self.paths["plex"]}/img/{os.path.dirname(end_path)}/default{img_format}' or \ 133 | f'{self.paths["plex"]}/img/btn/default{img_format}' 134 | 135 | return path 136 | 137 | 138 | # PLEX *************************************************************** 139 | @property 140 | def paths(self): 141 | return eval(os.environ['PLEX_PATHS']) 142 | 143 | @property 144 | def context(self): 145 | return eval(os.environ['PLEX_CONTEXT']) 146 | 147 | def set_context(self, key, value): 148 | context = eval(os.environ['PLEX_CONTEXT']) 149 | context[key] = value 150 | os.environ['PLEX_CONTEXT'] = str(context) 151 | 152 | 153 | # PROJECT ************************************************************ 154 | @property 155 | def project_names(self): 156 | projects_path = self.paths['config_projects'] 157 | return [os.path.basename(f.path) for f in os.scandir(projects_path) if f.is_dir()] 158 | 159 | 160 | # USER *************************************************************** 161 | @property 162 | def user_id(self): 163 | return getpass.getuser() 164 | 165 | @property 166 | def admin(self): 167 | return eval(os.environ['PLEX_CONTEXT'])['admin'] 168 | 169 | @property 170 | def user_sandbox(self): 171 | user_sandbox_path = f'{self.config["project"]["PATH"]["sandbox"]}/{self.user_id}' 172 | plexfunc.create_dir(user_sandbox_path) 173 | return user_sandbox_path 174 | 175 | 176 | # BUTTON ************************************************************** 177 | def help(self, name=''): 178 | name = name or self.software_name 179 | webbrowser.open(self.config['project']['URL'].get(name, self.config['project']['URL']['default'])) 180 | 181 | 182 | # Redirect module to singleton instance 183 | sys.modules[__name__] = Plex() -------------------------------------------------------------------------------- /scripts/plexlog.py: -------------------------------------------------------------------------------- 1 | # content = write loggings into console and files 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import sys 9 | import getpass 10 | import logging 11 | import logging.config 12 | 13 | # GET log file path 14 | # Plex: C:/plex/config/users/$user/$user.log 15 | # Else: C:/Users/$user/$user.log 16 | USER = getpass.getuser() 17 | plex_user_path = eval(os.environ.get('PLEX_PATHS', '{}')).get('config_user', os.path.expanduser('~')) 18 | USER_PATH = os.path.join(plex_user_path, f"{USER}.log") 19 | 20 | 21 | class ContextFilter(logging.Filter): 22 | USERS = USER 23 | 24 | def filter(self, record): 25 | record.user = ContextFilter.USERS 26 | return True 27 | 28 | 29 | # LOGGING ************************************************************* 30 | def init(software="default", script="default", level=logging.DEBUG, path="", 31 | debug_console=False, multi_threads=False, *args, **kwargs): 32 | 33 | path = path or USER_PATH 34 | create_folder(path) 35 | 36 | # OPTIONAL: separate levels into different files 37 | info_path, error_path, debug_path = path, path, path 38 | 39 | logging_config = dict( 40 | version= 1, 41 | disable_existing_loggers= False, 42 | formatters= { 43 | "simple": { 44 | "format": "%(asctime)s | %(user)-10s | %(module)-12s | %(levelname)-7s - %(lineno)-4d | %(message)s", 45 | "datefmt":"%d.%m.%Y %H:%M:%S" 46 | }, 47 | "simpleInfo": { 48 | "format": "%(asctime)s | %(levelname)-7s | %(user)-10s | %(module)-12s - %(funcName)-20s | %(lineno)-4d | %(message)s", 49 | "datefmt":"%d.%m.%Y %H:%M:%S" 50 | }, 51 | "simpleDebug": { 52 | "format": "%(asctime)s | %(levelname)-7s | %(module)-12s - %(funcName)-20s | %(lineno)-4d | %(message)s", 53 | "datefmt":"%d.%m.%Y %H:%M:%S" 54 | }, 55 | "threadsDebug": { 56 | "format": "%(asctime)s | %(levelname)-7s | %(threadName)-10s | %(module)-12s - %(funcName)-20s | %(lineno)-4d | %(message)s", 57 | "datefmt":"%d.%m.%Y %H:%M:%S" 58 | }, 59 | "simpleConsole": { 60 | "format": "%(asctime)s | %(levelname)-7s | %(message)s", 61 | "datefmt":"%H:%M:%S" } 62 | } 63 | ) 64 | 65 | logger = logging.getLogger(script) 66 | logger.propagate = False 67 | 68 | if not logger.handlers: 69 | # CONSOLE 70 | console_handler = logging.StreamHandler(stream=sys.stdout) 71 | formatter = logging.Formatter(logging_config["formatters"]["simpleConsole"]["format"], logging_config["formatters"]["simpleConsole"]["datefmt"]) 72 | console_handler.setFormatter(formatter) 73 | if debug_console: console_handler.setLevel(level) 74 | else: console_handler.setLevel(logging.INFO) 75 | logger.addHandler(console_handler) 76 | 77 | # DEBUG 78 | if level == logging.DEBUG: 79 | debug_handler = logging.handlers.RotatingFileHandler(debug_path, mode='a', maxBytes=10485760, backupCount=20, encoding="utf8") 80 | if multi_threads: formatter = logging.Formatter(logging_config["formatters"]["threadsDebug"]["format"], logging_config["formatters"]["simpleDebug"]["datefmt"]) 81 | else: formatter = logging.Formatter(logging_config["formatters"]["simpleDebug"]["format"], logging_config["formatters"]["threadsDebug"]["datefmt"]) 82 | debug_handler.setFormatter(formatter) 83 | debug_handler.setLevel(level) 84 | logger.addHandler(debug_handler) 85 | 86 | # INFO, WARNING, ERROR 87 | else: # level == logging.INFO: 88 | info_handler = logging.handlers.RotatingFileHandler(info_path, mode='a', maxBytes=10485760, backupCount=20, encoding="utf8") 89 | formatter = logging.Formatter(logging_config["formatters"]["simpleInfo"]["format"], logging_config["formatters"]["simple"]["datefmt"]) 90 | info_handler.setFormatter(formatter) 91 | info_handler.setLevel(level) 92 | logger.addHandler(info_handler) 93 | 94 | logger.setLevel(level) 95 | logger.addFilter(ContextFilter()) 96 | 97 | return logger 98 | 99 | 100 | def create_folder(path): 101 | if len(path.split('.')) > 1: 102 | path = os.path.dirname(path) 103 | 104 | if not os.path.exists(path): 105 | try: os.makedirs(path) 106 | except: print(f"CAN'T create folder: {path}") 107 | 108 | 109 | # USE 110 | # import plexlog 111 | # LOG = plexlog.init(__name__) 112 | # LOG.info('This works') -------------------------------------------------------------------------------- /scripts/plexstart.py: -------------------------------------------------------------------------------- 1 | # content = plex startup 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import sys 9 | import pathlib 10 | import getpass 11 | 12 | import plex 13 | import plexfunc 14 | 15 | from extern.Qt import QtWidgets, QtCore 16 | QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_ShareOpenGLContexts) 17 | 18 | 19 | # SETUP ************************************************************** 20 | def setup(project_id='default'): 21 | scripts_path = str(pathlib.Path(os.path.dirname(__file__)).resolve()) 22 | config_path = f'{os.path.dirname(scripts_path)}/config' 23 | plex_path = str(pathlib.Path(os.path.dirname(os.path.dirname(__file__))).resolve()) 24 | 25 | # LOAD plex config 26 | plex_config = plexfunc.get_yaml_content(f'{config_path}/plex.yml') 27 | project_yaml_path = f'{config_path}/projects/{project_id}/project.yml' 28 | 29 | if not os.path.exists(project_yaml_path): 30 | print(f'WARNING: Set to default project. Project config doesn\'t exist: {project_yaml_path}') 31 | project_yaml_path = f'{config_path}/projects/default/project.yml' 32 | 33 | project_config = plexfunc.get_yaml_content(project_yaml_path) 34 | 35 | plex_paths = {'plex' : os.path.dirname(config_path), 36 | 37 | 'config' : f'{config_path}/', 38 | 'config_users' : f'{config_path}/users/', 39 | 'config_user' : f'{config_path}/users/{getpass.getuser()}/', 40 | 'config_projects' : f'{config_path}/projects/', 41 | 'config_project' : f'{os.path.dirname(project_yaml_path)}/', 42 | 43 | 'img' : f'{plex_path}/img/', 44 | 45 | 'scripts' : scripts_path, 46 | 'extern' : f'{scripts_path}/extern/', 47 | 48 | 'apps' : f'{plex_path}/apps/', 49 | 'apps_extern' : f'{plex_path}/apps/extern', 50 | 51 | 'software' : f'{plex_path}/software/', 52 | 53 | 'project_pipeline' : project_config['PATH']['pipeline'], 54 | } 55 | 56 | plex_context = {'name' : plex_config['name'], # Plex 57 | 'description' : plex_config['description'], # Open Source Pipeline 58 | 'version' : plex_config['version'], # 2.5.0. 59 | 'credit' : plex_config['credit'], # Alexander Richter 60 | 61 | 'announcement' : plex_config['announcement'], 62 | 63 | 'project_id' : project_id, # default 64 | 'project_name' : project_config['name'], # Plex default 65 | 'project_path' : project_config['PATH']['project'], # D:/project 66 | 67 | 'software' : '', # maya, max, nuke, houdini 68 | 69 | 'resolution' : project_config['SETTING']['resolution'], # [1920, 1080] 70 | 'fps' : project_config['SETTING']['fps'], # 24 71 | 72 | 'user_id' : getpass.getuser(), # arichter 73 | 'admin' : True if getpass.getuser() in plex_config['admin'] else False, # True or False 74 | 75 | 'file_name' : '', # mike_RIG_v012 76 | 'file_path' : '', # D:/project/asset/mike_RIG_v012.mb 77 | 'file_extension' : '', # mb 78 | 79 | 'step' : '', # shots or assets or renders 80 | 'scene' : '', # s010 or mike 81 | 'task' : '', # ANIMATION 82 | 'status' : '', # WORK or PUBLISH 83 | } 84 | 85 | 86 | os.environ['PLEX_PATHS'] = str(plex_paths) 87 | os.environ['PLEX_CONTEXT'] = str(plex_context) 88 | 89 | # PATH env: Add plex_paths 90 | sys.path.extend(plex_paths.values()) 91 | plex.config_refresh() 92 | 93 | plex_print() 94 | 95 | 96 | def plex_print(): 97 | LOG = plex.log(script=__name__) 98 | 99 | LOG.debug('') 100 | LOG.debug(200 * '_') 101 | LOG.debug(f'PLEX: {os.environ["PLEX_PATHS"]}') 102 | LOG.debug(f'CONTEXT: {os.environ["PLEX_CONTEXT"]}') 103 | LOG.debug(f"SYS_PATH: {'[%s]' % ', '.join(map(str, sys.path))}") 104 | LOG.debug(200 * '-') 105 | 106 | 107 | def show_splashscreen(): 108 | app = QtWidgets.QApplication.instance() 109 | if not app: 110 | app = QtWidgets.QApplication(sys.argv) 111 | 112 | import arSplash 113 | splash = arSplash.ArSplash() 114 | 115 | # Process events until splash closes 116 | while splash.wgSplash.isVisible(): 117 | app.processEvents() 118 | 119 | return app 120 | 121 | 122 | # START ************************************************************** 123 | import argparse 124 | 125 | parser = argparse.ArgumentParser(description='Setup your Plex and start software.') 126 | parser.add_argument('-s','--software', help='start software: desktop/nuke/max/maya/houdini') 127 | args = parser.parse_args() 128 | 129 | if args.software: 130 | setup() 131 | app = show_splashscreen() 132 | 133 | if args.software == 'desktop': 134 | import arDesktop 135 | arDesktop.start() 136 | else: 137 | plex.software.start(name=args.software) 138 | 139 | sys.exit(0) -------------------------------------------------------------------------------- /scripts/snapshot.py: -------------------------------------------------------------------------------- 1 | # content = snapshot 2 | # executes other scripts on PUBLISH (on task in file name) 3 | # date = 03.12.2024 4 | # 5 | # license = MIT 6 | # author = Alexander Richter 7 | 8 | import os 9 | 10 | from Qt import QtWidgets, QtGui, QtCore, __binding__ 11 | 12 | import plexfunc 13 | import plex 14 | 15 | # VARIABLE *********************************************************** 16 | LOG = plex.log(script=__name__) 17 | DEFAULT_PATH = os.path.normpath(plex.get_config('config_user') + '/tmp_img.jpg') 18 | 19 | 20 | # SCREENSHOT ********************************************************* 21 | # creates a screenshot of the main screen and saves it 22 | def create_any_screenshot(WIDGET, ui=''): 23 | # if not create_screenshot_render(WIDGET, ui): 24 | if not create_screenshot_viewport(WIDGET, ui): 25 | create_screenshot(WIDGET, ui) 26 | 27 | 28 | def create_screenshot(WIDGET, ui=''): 29 | print("SCREENSHOT") 30 | # WIDGET.hide() 31 | if not os.path.exists(os.path.dirname(DEFAULT_PATH)): 32 | try: os.makedirs(os.path.dirname(DEFAULT_PATH)) 33 | except: LOG.error('FAILED folder creation', exc_info=True) 34 | # time.sleep(0.6) 35 | 36 | if __binding__ == "PySide2": 37 | from PySide2 import QtWidgets, QtGui 38 | QtGui.QScreen.grabWindow(QtWidgets.QApplication.primaryScreen(), QtWidgets.QApplication.desktop().winId()).save(DEFAULT_PATH, DEFAULT_PATH.split(".")[-1]) 39 | else: 40 | from Qt import QtWidgets, QtGui 41 | QtGui.QPixmap.grabWindow(QtWidgets.QApplication.desktop().winId()).save(DEFAULT_PATH, DEFAULT_PATH.split(".")[-1]) 42 | 43 | # WIDGET.setFocus() 44 | # WIDGET.show() 45 | if ui: ui.setIcon(QtGui.QPixmap(QtGui.QImage(DEFAULT_PATH))) 46 | 47 | 48 | def create_screenshot_render(WIDGET, ui=''): 49 | # WIDGET.hide() 50 | if not os.path.exists(os.path.dirname(DEFAULT_PATH)): 51 | try: 52 | os.makedirs(os.path.dirname(DEFAULT_PATH)) 53 | except: 54 | LOG.error('FAILED folder creation', exc_info=True) 55 | return False 56 | 57 | try: 58 | if plex.software.is_software('maya'): 59 | if not maya_renderSnapshot(DEFAULT_PATH)[1]: 60 | LOG.warning("no snapshot no") 61 | return False 62 | elif plex.is_software('houdini'): 63 | houdini_renderSnapshot(DEFAULT_PATH) 64 | else: 65 | return False 66 | except: 67 | LOG.error('FAIL', exc_info=True) 68 | return False 69 | 70 | if ui and os.path.exists(DEFAULT_PATH): ui.setIcon(QtGui.QPixmap(QtGui.QImage(DEFAULT_PATH))) 71 | # WIDGET.show() 72 | # WIDGET.setFocus() 73 | return True 74 | 75 | 76 | def create_screenshot_viewport(WIDGET, ui=''): 77 | # WIDGET.hide() 78 | plex.software.viewport_snapshot() 79 | 80 | # TODO: FIX for 81 | # "HOUDINI": create_screenshot(WIDGET, ui) # houdini_viewportSnapshot(DEFAULT_PATH) 82 | # "MAX": create_screenshot(WIDGET, ui) 83 | 84 | if ui and os.path.exists(DEFAULT_PATH): 85 | ui.setIcon(QtGui.QPixmap(QtGui.QImage(DEFAULT_PATH))) 86 | else: 87 | return False 88 | # WIDGET.show() 89 | # WIDGET.setFocus() 90 | return True 91 | 92 | 93 | # FILE HANDLING ****************************************************** 94 | def save_snapshot(rlt_path, src_path=DEFAULT_PATH): 95 | img = QtGui.QImage() 96 | img.load(src_path) 97 | thumbnail_extension = '.' + plex.config['project']['EXTENSION']['thumbnail'] 98 | 99 | tmp_dir = f'{os.path.dirname(rlt_path)}/{os.path.dirname(plex.paths["meta"])}' 100 | rlt_path = + f'{tmp_dir}/{os.path.basename(rlt_path).split(".")[0]}{thumbnail_extension}' 101 | 102 | plexfunc.create_dir(rlt_path) 103 | img.save(rlt_path, format=thumbnail_extension) 104 | remove_tmp_img(src_path) 105 | return rlt_path 106 | 107 | def remove_tmp_img(img_path=DEFAULT_PATH): 108 | try: os.remove(img_path) 109 | except: LOG.error(f'FAIL : cant delete tmpFile : {img_path}', exc_info=True) 110 | -------------------------------------------------------------------------------- /scripts/software.py: -------------------------------------------------------------------------------- 1 | # content = setup software attributes 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import sys 9 | import getpass 10 | import subprocess 11 | 12 | import plexfunc 13 | import plex 14 | 15 | LOG = plex.log(script=__name__) 16 | 17 | 18 | class Software(plexfunc.Singleton): 19 | def start(self, name='', open_file=''): 20 | plex.set_context('software', name) 21 | 22 | # SETUP env 23 | software_dirs = plexfunc.get_sub_dirs(self.path, full_path=True) 24 | 25 | os.environ['SOFTWARE_PATH'] = ';'.join(software_dirs) 26 | # PYTHONPATH important for software imports 27 | os.environ['PYTHONPATH'] = ';'.join([ 28 | os.environ.get('PYTHONPATH', ''), 29 | *software_dirs, 30 | f'{plex.paths["software"]}/{self.name}', 31 | plex.paths["scripts"], 32 | plex.paths["apps"], 33 | plex.paths["extern"], 34 | ]) 35 | 36 | sys.path.extend(software_dirs) 37 | 38 | # GET software config 39 | self.env = plex.config['software'].get('ENV', '') 40 | 41 | # ADD software ENV 42 | for env, content in self.env.items(): 43 | if isinstance(content, list): 44 | [plexfunc.add_env(env, each) for each in content] 45 | else: 46 | plexfunc.add_env(env, content) 47 | 48 | if open_file: open_file = f'"{open_file}"' 49 | cmd = plex.config['software']['start'].format(open_file) 50 | subprocess.Popen(cmd, shell=True, env=os.environ) 51 | 52 | LOG.debug(f'START : {self.name.upper()} : {cmd}') 53 | self.print_header() 54 | 55 | 56 | # VARIABLES *********************************************************** 57 | @property 58 | def id(self): 59 | return id(self) 60 | 61 | @property 62 | def name(self): 63 | return plex.context['software'] 64 | 65 | @property 66 | def path(self): 67 | return f'{plex.paths["software"]}/{self.name}' 68 | 69 | @property 70 | def config(self): 71 | return plex.config['software'] 72 | 73 | @property 74 | def extension(self): 75 | return plex.config['project']['EXTENSION'][self.name] 76 | 77 | @property 78 | def menu(self): 79 | return plex.config['software']['MENU'] 80 | 81 | @property 82 | def version(self): 83 | return plex.config['software']['version'] 84 | 85 | @property 86 | def renderer(self): 87 | return plex.config['software'].get('renderer', '') 88 | 89 | @property 90 | def renderer_path(self): 91 | return plex.config['software'].get('renderer_path', '') 92 | 93 | 94 | #********************************************************************* 95 | # FUNCTION 96 | def is_software(self, software_name): 97 | return self.name == software_name 98 | 99 | def create_menu(self): 100 | print('NO menu create') 101 | 102 | def delete_menu(self): 103 | print('NO menu deleted') 104 | 105 | 106 | @property 107 | def scene_path(self): 108 | print('NO scene_path software override found') 109 | 110 | def scene_save(self): 111 | print('NO scene_save software override found') 112 | 113 | def scene_save_as(self, file): 114 | print('NO scene_save_as software override found') 115 | 116 | def scene_open(self, file): 117 | print('NO scene_open software override found') 118 | 119 | def scene_import(self, file): 120 | print('NO scene_import software override found') 121 | 122 | 123 | #********************************************************************* 124 | # PRINT 125 | def print_header(self): 126 | if self.is_software('max'): return 127 | 128 | project_len = len(plex.context['project_name']) 129 | space = (20-int(project_len/2)) - 1 130 | 131 | # project name 132 | print('') 133 | print(chr(124) + '-' * (2 * space + project_len) + chr(124)) 134 | print(chr(124) + ' ' * space + plex.context['project_name'] + ' ' * space + chr(124)) 135 | print(chr(124) + '-' * (2 * space + project_len) + chr(124)) 136 | 137 | # user name & software 138 | space = (21-int(len('Welcome ' + getpass.getuser())/2)) - 1 139 | print(' ' * space + 'Welcome ' + getpass.getuser()) 140 | print('') 141 | space = (20-int(len(f'{self.name} {self.version}')/2)) - 1 142 | print(' ' * space + f'{self.name.title()} {self.version}') 143 | 144 | print(f'\n\n{plex.paths["plex"]}') 145 | print('\n• img') 146 | print('• scripts') 147 | print(r'• apps') 148 | print(r'• scripts\extern') 149 | 150 | print(f'\n• config\\projects\\{plex.context["project_id"]}\n') 151 | 152 | print(fr'• software\{self.name}') 153 | for sub_dir in plexfunc.get_sub_dirs(self.path): 154 | print(fr'• software\{self.name}\{sub_dir}') 155 | 156 | print('') 157 | 158 | LOG.debug(f'SOFTWARE: {self.name} {self.version} : {self.path} | ENV: {self.env}') 159 | LOG.debug(f'PYTHONPATH: {os.environ["PYTHONPATH"]}') 160 | -------------------------------------------------------------------------------- /software/houdini/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/houdini/__init__.py -------------------------------------------------------------------------------- /software/houdini/init/MainMenuMaster.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | $SOFTWARE_PATH/menu.py 12 | save 13 | 14 | 15 | 16 | 17 | 18 | 19 | $SOFTWARE_PATH/menu.py 20 | get_report 21 | 22 | 23 | 24 | 25 | $SOFTWARE_PATH/menu.py 26 | get_help 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /software/houdini/init/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/houdini/init/__init__.py -------------------------------------------------------------------------------- /software/houdini/init/init.py: -------------------------------------------------------------------------------- 1 | # content = houdini init 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import plex 8 | 9 | LOG = plex.log(script=__name__) 10 | 11 | 12 | def add_menu(): 13 | menu_path = f'{plex.paths["software"]}/houdini/scripts/MainMenuMaster.xml' 14 | 15 | def find_inbetween(self, text, first, last): 16 | try: 17 | return text.split(first, 1)[1].split(last, 1)[0] 18 | except (IndexError, ValueError): 19 | return "" 20 | 21 | try: 22 | with open(menu_path, 'r+') as outfile: 23 | content = outfile.read() 24 | find_title = find_inbetween(content, '') 25 | content = content.replace(f'', f'') 26 | print(content) 27 | # WRITE new XML 28 | outfile.seek(0) 29 | outfile.write(content) 30 | outfile.truncate() 31 | except: LOG.error(f'FILE not found: {menu_path}', exc_info=True) 32 | -------------------------------------------------------------------------------- /software/houdini/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/houdini/plugins/__init__.py -------------------------------------------------------------------------------- /software/houdini/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/houdini/scripts/__init__.py -------------------------------------------------------------------------------- /software/houdini/scripts/houdini_dcc.py: -------------------------------------------------------------------------------- 1 | # content = Houdini 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | 8 | import plex 9 | from software import Software 10 | 11 | LOG = plex.log(script=__name__) 12 | 13 | 14 | class Houdini(Software): 15 | 16 | _NAME = 'houdini' 17 | -------------------------------------------------------------------------------- /software/max/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/max/__init__.py -------------------------------------------------------------------------------- /software/max/init/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/max/init/__init__.py -------------------------------------------------------------------------------- /software/max/init/startup.ms: -------------------------------------------------------------------------------- 1 | 2 | -- ... because Autodesk 3 | python.init() 4 | python.ExecuteFile "startup.py" 5 | -------------------------------------------------------------------------------- /software/max/init/startup.py: -------------------------------------------------------------------------------- 1 | # content = startup 3Ds Max 2 | # date = 2020-06-19 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import shutil 9 | 10 | import MaxPlus 11 | 12 | import plex 13 | 14 | 15 | # VARIABLE *************************************************************** 16 | LOG = plex.log(script=__name__) 17 | menu_name = plex.context['project_name'] 18 | plex.init_software() 19 | 20 | 21 | # MENU *************************************************************** 22 | def create_menu(): 23 | # copy_splash() 24 | delete_menu() 25 | 26 | if MaxPlus.MenuManager.MenuExists(menu_name): 27 | print('The menu ', menu_name, ' already exists') 28 | else: 29 | menu = MaxPlus.MenuBuilder(menu_name) 30 | # create menu 31 | 32 | def delete_menu(): 33 | MaxPlus.MenuManager.UnregisterMenu(unicode(menu_name)) 34 | 35 | 36 | def copy_splash(): 37 | splash_path = plex.get_img_path("software/max/splash.bmp") 38 | max_path = os.path.dirname(plex.software.config['path']) 39 | 40 | if not os.path.exists(max_path + '/splash.bmp'): 41 | try: 42 | shutil.copy(splash_path, max_path) 43 | except: 44 | LOG.error(f'FAILED to copy splash: {max_path}', exc_info=True) 45 | -------------------------------------------------------------------------------- /software/max/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/max/plugins/__init__.py -------------------------------------------------------------------------------- /software/max/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/max/scripts/__init__.py -------------------------------------------------------------------------------- /software/max/scripts/max_dcc.py: -------------------------------------------------------------------------------- 1 | # content = 3ds Max 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | 9 | import MaxPlus 10 | 11 | import plexfunc 12 | import plex 13 | from software import Software 14 | 15 | LOG = plex.log(script=__name__) 16 | 17 | 18 | class Max(Software): 19 | 20 | _NAME = 'max' 21 | 22 | @property 23 | def scene_path(self): 24 | return MaxPlus.Core.EvalMAXScript("maxFilePath + maxFileName").Get() 25 | 26 | def scene_save(self): 27 | return MaxPlus.FileManager.Save() 28 | 29 | def scene_save_as(self, file, setup_scene=False): 30 | return MaxPlus.FileManager.Save(file) 31 | 32 | def scene_open(self, file): 33 | return MaxPlus.FileManager.Open(file) 34 | 35 | def scene_import(self, file): 36 | pass 37 | 38 | 39 | # MENU *************************************************************** 40 | def open_scene_folder(): 41 | plexfunc.open_dir(MaxPlus.Core.EvalMAXScript("sceneName = maxFilePath + maxFileName").Get()) 42 | 43 | def open_project_folder(): 44 | plexfunc.open_dir(os.getenv("PROJECT_PATH")) 45 | 46 | def save(): 47 | import arSave 48 | arSave.start() 49 | 50 | def load(): 51 | import arLoad 52 | arLoad.start() 53 | 54 | def get_report(): 55 | plex.help('report') 56 | 57 | def get_help(): 58 | plex.help() 59 | -------------------------------------------------------------------------------- /software/maya/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/__init__.py -------------------------------------------------------------------------------- /software/maya/init/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/init/__init__.py -------------------------------------------------------------------------------- /software/maya/init/userSetup.py: -------------------------------------------------------------------------------- 1 | # content = setup maya 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import maya.cmds as cmds 8 | 9 | import plex 10 | 11 | LOG = plex.log(script=__name__) 12 | 13 | 14 | cmds.evalDeferred('print("")') 15 | cmds.evalDeferred('print("START PLEX -------------------------------------")') 16 | cmds.evalDeferred(f'import plex; plex.software.create_menu()') 17 | 18 | cmds.evalDeferred('print("FINISH -----------------------------------------")') 19 | cmds.evalDeferred('print("")') 20 | 21 | 22 | -------------------------------------------------------------------------------- /software/maya/maya_dcc.py: -------------------------------------------------------------------------------- 1 | # content = Maya 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import maya.mel as mel 8 | import maya.cmds as cmds 9 | 10 | import plex 11 | from software import Software 12 | 13 | LOG = plex.log(script=__name__) 14 | 15 | 16 | class Maya(Software): 17 | menu_name = plex.config['plex']['name'] 18 | name = 'maya' 19 | 20 | @property 21 | def scene_path(self): 22 | return cmds.file(query=True, sceneName=True) 23 | 24 | def scene_save(self, file_path): 25 | cmds.file(rename=file_path) 26 | return cmds.file(save=True) 27 | 28 | def scene_open(self, file_path): 29 | return cmds.file(file_path, open=True, force=True) 30 | 31 | def scene_import(self, file_path): 32 | return cmds.file(file_path, i=True) 33 | 34 | def scene_reference(self, file_path): 35 | return cmds.file(file_path, reference=True) 36 | 37 | 38 | # MENU *************************************************************** 39 | def create_menu(self): 40 | self.delete_menu() 41 | print('create menu: Maya') 42 | 43 | menu = cmds.menu(self.menu_name, parent='MayaWindow', label=self.menu_name, helpMenu=True, tearOff=True) 44 | 45 | menu_config = plex.config['software']['MENU'] 46 | LOG.debug(f'Menu items: {menu_config}') 47 | 48 | for menu_item in menu_config: 49 | for key, value in menu_item.items(): 50 | if isinstance(value, list): 51 | sub_menu = cmds.menuItem(parent=menu, label=key, subMenu=True) 52 | for sub_item in value: 53 | for label, command in sub_item.items(): 54 | if label == 'break': 55 | cmds.menuItem(parent=sub_menu, divider=True) 56 | else: 57 | cmds.menuItem(parent=sub_menu, label=label, command=command) 58 | else: 59 | if key == 'break': 60 | cmds.menuItem(parent=menu, divider=True) 61 | else: 62 | cmds.menuItem(parent=menu, label=key, command=value) 63 | 64 | 65 | def delete_menu(self): 66 | if cmds.menu(self.menu_name, query=True, exists=True): 67 | cmds.deleteUI(self.menu_name, menu=True) 68 | 69 | # # reference or open 70 | # if ref or ".abc" in self.save_dir or ".obj" in self.save_dir or ".fbx" in self.save_dir: 71 | # # file -r -type "mayaBinary" -ignoreVersion -gl -mergeNamespacesOnClash false -namespace "bull_MODEL_v004_jo" -options "v=0;" "K:/30_assets/bull/10_MODEL/WORK/bull_MODEL_v004_jo.mb"; 72 | # mel.eval('file -r -type "' + s.FILE_FORMAT_CODE["." + self.save_dir.split(".")[-1]] + '" -ignoreVersion -gl -mergeNamespacesOnClash false "' + self.save_dir.replace("\\", "/") + '"') 73 | 74 | 75 | # SNAPSHOT *************************************************************** 76 | def viewport_snapshot(self, img_path): 77 | mel.eval('setAttr "defaultRenderGlobals.imageFormat" 8;') 78 | 79 | # playblast one frame to a specific file 80 | currentFrame = str(cmds.currentTime(q=1)) 81 | snapshotStr = 'playblast -frame ' + currentFrame + ' -format "image" -cf "' + img_path + '" -v 0 -wh 1024 576 -p 100;' 82 | mel.eval(snapshotStr) 83 | 84 | # restore the old format 85 | mel.eval('setAttr "defaultRenderGlobals.imageFormat" `getAttr "defaultRenderGlobals.imageFormat"`;') 86 | LOG.info("maya_viewport_snapshot") 87 | 88 | 89 | def render_snapshot(self, img_path): 90 | mel.eval('setAttr "defaultRenderGlobals.imageFormat" 8;') 91 | 92 | LOG.info("maya_render_snapshot") 93 | return cmds.renderWindowEditor('renderView', e=True, writeImage=img_path) 94 | -------------------------------------------------------------------------------- /software/maya/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/plugins/__init__.py -------------------------------------------------------------------------------- /software/maya/scripts/ANIM/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/scripts/ANIM/__init__.py -------------------------------------------------------------------------------- /software/maya/scripts/ANIM/playblast.py: -------------------------------------------------------------------------------- 1 | # content = create playblast 2 | # executes other scripts on PUBLISH (on task in file name) 3 | # date = 2020-06-19 4 | # 5 | # license = MIT 6 | # author = Alexander Richter 7 | 8 | 9 | import os 10 | from os import startfile 11 | 12 | import maya.mel as mel 13 | import maya.cmds as cmds 14 | 15 | import plex 16 | 17 | LOG = plex.log(script=__name__) 18 | 19 | 20 | def start(): 21 | LOG.info("CREATE playblast") 22 | file_path = cmds.file(q=True, sn=True) 23 | 24 | if not file_path: 25 | LOG.warning("No Save Path") 26 | return 27 | 28 | save_path = os.path.dirname(file_path) + "/" + "playblast" + "/" + os.path.basename(file_path).split(".")[0] + '.' + plex.config['project']['EXTENSION']['playblast'] 29 | mel.eval(f'playblast -format avi -filename "{save_path}" -forceOverwrite -sequenceTime 0 -clearCache 1 -viewer 1 -showOrnaments 1 -fp 4 -percent 100 -compression "none" -quality 100;') 30 | 31 | startfile(os.path.normpath(save_path)) 32 | 33 | 34 | def turntable(): 35 | pass 36 | -------------------------------------------------------------------------------- /software/maya/scripts/LGT/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/scripts/LGT/__init__.py -------------------------------------------------------------------------------- /software/maya/scripts/LGT/light_linker.py: -------------------------------------------------------------------------------- 1 | # content = Maya: Light Linker 2 | # date = 2020-06-19 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import maya.cmds as cmds 8 | 9 | import plex 10 | 11 | LOG = plex.log(script=__name__) 12 | 13 | 14 | # LIGHT LINKER *************************************************************** 15 | def start(): 16 | cmds.window(title='Light Linker') 17 | cmds.columnLayout() 18 | cmds.rowLayout(numberOfColumns=2) 19 | cmds.text(label='Light', width=300, height=30) 20 | # cmds.text(label='Shadow', width=300, height=30) 21 | cmds.setParent('..') 22 | cmds.rowLayout(numberOfColumns=2) 23 | cmds.button(label="Add Lights", annotation="Add link between objects and lights", width=300, c="light_linker.selection_light_linking()") 24 | # cmds.button(label="Add Shadows", annotation="Add link between objects and shadows", width=300, c="light_linker.selection_light_linking(shadow_link=True)") 25 | cmds.setParent('..') 26 | cmds.rowLayout(numberOfColumns=2) 27 | cmds.button(label="Break Lights", annotation="Break link between objects and lights", width=300, c="light_linker.selection_light_linking(break_light=True)") 28 | # cmds.button(label="Break Shadows", annotation="Break link between objects and shadows", width=300, c="light_linker.selection_light_linking(break_light=True, shadow_link=True)") 29 | cmds.setParent('..') 30 | cmds.separator(height=10) 31 | cmds.rowLayout(numberOfColumns=2) 32 | cmds.button(label="Objects exclusive to this lights", annotation="Objects will only linked to this lights", width=300, c="light_linker.selection_light_linking(exclusive='lights')") 33 | # cmds.button(label="Link (Shadow Exclusive)", annotation="Objects will only linked to this shadows", width=300, c="light_linker.selection_light_linking(exclusive='lights', shadow_link=True)") 34 | cmds.setParent('..') 35 | cmds.rowLayout(numberOfColumns=2) 36 | cmds.button(label="Lights exclusive to this objects", annotation="Lights will only be linked to this objects", width=300, c="light_linker.selection_light_linking(exclusive='meshes')") 37 | # cmds.button(label="Link (Object Exclusive)", annotation="Shadows will only be linked to this objects", width=300, c="light_linker.selection_light_linking(exclusive='meshes', shadow_link=True)") 38 | cmds.setParent('..') 39 | cmds.separator(height=10) 40 | cmds.rowLayout(numberOfColumns=2) 41 | cmds.button(label="Select Linked Lights/Objects", annotation="Select the linked lights/meshes", width=300, c="light_linker.select_attached()") 42 | # cmds.button(label="Select Linked Shadows", annotation="Select the linked lights/meshes", width=300, c="light_linker.select_attached(shadow_link=True)") 43 | cmds.setParent('..') 44 | cmds.columnLayout() 45 | 46 | cmds.showWindow() 47 | 48 | 49 | def selection_light_linking(break_light=False, exclusive="", shadow_link=False): 50 | selection = cmds.ls(dag=1,o=1,s=1,sl=1) 51 | lights = cmds.ls(selection, type=["light"] + cmds.listNodeTypes("light")) 52 | meshes = list(set(selection) - set(lights)) 53 | 54 | if not selection or not lights: return "error:no_light_selection" 55 | 56 | if exclusive == "lights": 57 | scene_lights = cmds.ls(type=["light"] + cmds.listNodeTypes("light")) 58 | exclude_lights = list(set(scene_lights) - set(lights)) 59 | cmds.lightlink(light=exclude_lights, object=meshes, shadow=shadow_link, b=True) 60 | 61 | LOG.info(f"exclude_lights: {exclude_lights}") 62 | elif exclusive == "meshes": 63 | exclude_meshes = list(set(cmds.ls(dag=1,o=1,s=1)) - set(meshes)) 64 | cmds.lightlink(light=lights, object=exclude_meshes, shadow=shadow_link, b=True) 65 | 66 | LOG.info(f"exclude_meshes: {exclude_meshes}") 67 | 68 | if not meshes: 69 | cmds.lightlink(light=lights, object=cmds.ls(dag=1,o=1,s=1), shadow=shadow_link) 70 | LOG.info(f"LightLinking: Default for {lights}") 71 | return 72 | 73 | cmds.lightlink(light=lights, object=meshes, shadow=shadow_link, b=break_light) 74 | LOG.debug(f"LightLinking - break:{break_light} - shadow:{shadow_link}: {lights} with {meshes}") 75 | 76 | 77 | def select_attached(shadow_link=False): 78 | selection = cmds.ls(dag=1,o=1,s=1,sl=1) 79 | lights = cmds.ls(selection, type=["light"] + cmds.listNodeTypes("light")) 80 | selection = cmds.pickWalk(direction='down') 81 | 82 | if not selection and not lights: 83 | return "error:no_light_selection" 84 | 85 | attached_objs = [] 86 | 87 | if lights: 88 | for sel in selection: 89 | attached_objs += cmds.lightlink(query=True, shadow=shadow_link, light=sel) 90 | select_nodes = cmds.ls(attached_objs, type=['mesh', 'nurbsSurface']) 91 | else: # MESHES 92 | for sel in selection: 93 | attached_objs += cmds.lightlink(query=True, shadow=shadow_link, object=selection) 94 | select_nodes = cmds.ls(attached_objs, type=["light"] + cmds.listNodeTypes("light")) 95 | 96 | if not select_nodes: return 97 | 98 | cmds.select(select_nodes) 99 | cmds.pickWalk(direction='up') 100 | -------------------------------------------------------------------------------- /software/maya/scripts/SHD/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/scripts/SHD/__init__.py -------------------------------------------------------------------------------- /software/maya/scripts/SHD/create_shader.py: -------------------------------------------------------------------------------- 1 | # content = shader 2 | # date = 2020-06-19 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import maya.cmds as cmds 8 | 9 | 10 | def create_simple_shd(name="BLACK_SHD", color=[0,0,0]): 11 | if cmds.objExists(name): 12 | print(f"CREATED - {name}") 13 | else: 14 | shader = cmds.shadingNode("surfaceShader", name=name, asShader=True) 15 | cmds.setAttr(shader + '.outColor', color[0], color[1], color[2]) 16 | print(f"EXISTS - {name}") 17 | 18 | return shader 19 | -------------------------------------------------------------------------------- /software/maya/scripts/SHD/unite_shader_group.py: -------------------------------------------------------------------------------- 1 | # content = sets the name of all shader groups as the shader (+SG) 2 | # date = 2020-06-19 3 | 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import maya.mel as mel 8 | import maya.cmds as cmds 9 | from pymel.core import * 10 | 11 | import plex 12 | 13 | LOG = plex.log(script=__name__) 14 | 15 | 16 | def start(shader_types=["alSurface", "alLayer"]): 17 | shaders = [] 18 | 19 | for shader_type in shader_types: 20 | shaders += cmds.ls(type = shader_type) 21 | 22 | for shader in shaders: 23 | shader_groups = PyNode(shader).shadingGroups() 24 | 25 | if len(shader_groups) == 0: continue 26 | 27 | #START: ADDING 28 | shader_group = shader_groups[0] 29 | own_shader_roups = [] 30 | conns = connectionInfo(PyNode(shader).outColor, destinationFromSource = True) 31 | 32 | for conn in conns: 33 | connNode = PyNode(conn).node() 34 | 35 | if PyNode(connNode).nodeType() != "shadingEngine": 36 | continue 37 | else: 38 | own_shader_roups.append(str(connNode)) 39 | 40 | if not (shader_group in own_shader_roups): continue 41 | # END: ADDING 42 | 43 | if (shader_group != shader + "SG"): 44 | try: 45 | mel.eval('rename ' + shader_group + ' ' + shader + 'SG;') 46 | except: 47 | LOG.error("** FAIL | Unite Shader and Shader Group: Shader has no shading group or is a reference - " + shader + " **") 48 | 49 | LOG.info("DONE : Unite Shader and Shader Group") 50 | -------------------------------------------------------------------------------- /software/maya/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/maya/scripts/__init__.py -------------------------------------------------------------------------------- /software/maya/scripts/maya_utils.py: -------------------------------------------------------------------------------- 1 | # content = Maya utils 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | 9 | import maya.mel as mel 10 | import maya.cmds as cmds 11 | 12 | from functools import wraps 13 | 14 | import plex 15 | LOG = plex.log(__name__) 16 | 17 | 18 | # START SETUP *************************************************************** 19 | def setup_scene(file_path=''): 20 | # RESOLUTION 21 | try: 22 | cmds.setAttr("defaultResolution.width", plex.config['project']['resolution'][0]) 23 | cmds.setAttr("defaultResolution.height", plex.config['project']['resolution'][1]) 24 | cmds.setAttr('defaultResolution.deviceAspectRatio', (( plex.config['project']['resolution'][0]) / (plex.config['project']['resolution'][1]))) 25 | except: LOG.error('FAIL load resolution.', exc_info=True) 26 | 27 | # IMG FORMAT 28 | # try: 29 | # cmds.setAttr("defaultRenderGlobals.imageFormat", 8) 30 | # except: LOG.error('FAIL load img format.', exc_info=True) 31 | 32 | # FPS 33 | try: 34 | fps = plex.config['project']['fps'] 35 | cmds.currentUnit(time=fps) 36 | cmds.optionVar(sv = ("workingUnitTime", fps)) 37 | cmds.optionVar(sv = ("workingUnitTimeDefault", fps)) 38 | except: LOG.error('FAIL load fps.', exc_info=True) 39 | 40 | 41 | # RENDERER 42 | try: 43 | renderer = plex.config['project']['SETTINGS']['renderer'] 44 | cmds.optionVar(sv = ("preferredRenderer", renderer)) 45 | cmds.optionVar(sv = ("preferredRendererHold", renderer)) 46 | except: LOG.error('FAIL load renderer.', exc_info=True) 47 | 48 | # ANIMATION extension 49 | try: 50 | cmds.setAttr('defaultRenderGlobals.animation', 1) 51 | cmds.setAttr('defaultRenderGlobals.putFrameBeforeExt', 1) 52 | cmds.setAttr('defaultRenderGlobals.extensionPadding', 4) 53 | except: LOG.error('FAIL set extension.', exc_info=True) 54 | 55 | if file_path: 56 | try: 57 | render_path = os.path.dirname(os.path.dirname(file_path)) 58 | render_path += "/RENDER//" 59 | cmds.setAttr('defaultRenderGlobals.imageFilePrefix', render_path, type='string') 60 | except: LOG.error('FAIL set image path.', exc_info=True) 61 | 62 | try: 63 | pass 64 | # pm.mel.setProject(os.path.dirname(file_path)) 65 | except: LOG.error('FAIL set project path.', exc_info=True) 66 | 67 | # shortcut - SAVE 68 | # cmd = 'python "from scripts import save;save.start()"' 69 | # cmds.nameCommand( 'save', annotation="Save", sourceType="mel" ,c=cmd) 70 | # cmds.hotkey( k='s', alt=True, name='save' ) 71 | # import maya.OpenMaya as api 72 | 73 | # FIX renderLayer 74 | # def fixRenderLayer(*args): 75 | # mel.eval("fixRenderLayerOutAdjustmentErrors;") 76 | # api.MSceneMessage.addCallback(api.MSceneMessage.kAfterOpen, fixRenderLayer) 77 | 78 | 79 | # DECORATOR *************************************************************** 80 | def viewport_off(func): 81 | @wraps(func) 82 | def viewport(*args, **kwargs): 83 | try: 84 | # viewport OFF 85 | mel.eval("paneLayout -e -manage false $gMainPane") 86 | return func(*args, **kwargs) 87 | except Exception: 88 | LOG.error("FAIL : Viewport off", exc_info=True) 89 | raise 90 | finally: 91 | # viewport ON 92 | mel.eval("paneLayout -e -manage true $gMainPane") 93 | 94 | return viewport 95 | -------------------------------------------------------------------------------- /software/nuke/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/nuke/__init__.py -------------------------------------------------------------------------------- /software/nuke/gizmos/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/nuke/gizmos/__init__.py -------------------------------------------------------------------------------- /software/nuke/gizmos/arAlphaPlate.gizmo: -------------------------------------------------------------------------------- 1 | #! C:/Program Files/Nuke9.0v7/nuke-9.0.7.dll -nx 2 | version 9.0 v7 3 | Gizmo { 4 | } 5 | Input { 6 | inputs 0 7 | name Input1 8 | xpos -341 9 | ypos 482 10 | } 11 | Crop { 12 | box {0 0 1920 1080} 13 | reformat true 14 | crop false 15 | name Crop1 16 | selected true 17 | xpos -341 18 | ypos 522 19 | } 20 | Shuffle { 21 | alpha white 22 | name Shuffle5 23 | xpos -341 24 | ypos 564 25 | } 26 | Remove { 27 | operation keep 28 | channels rgba 29 | name Remove1 30 | xpos -341 31 | ypos 599 32 | } 33 | Output { 34 | name Output1 35 | xpos -341 36 | ypos 699 37 | } 38 | end_group 39 | -------------------------------------------------------------------------------- /software/nuke/gizmos/arLetterbox.gizmo: -------------------------------------------------------------------------------- 1 | #! C:/Program Files/Nuke9.0v7/nuke-9.0.7.dll -nx 2 | version 9.0 v7 3 | Gizmo { 4 | knobChanged "\n\ncurrentNode = nuke.thisNode()\n\n# THREADS\nif currentNode\[\"ddlLetterbox\"].value() == \"custom\":\n currentNode\[\"edtX\"].setVisible(True)\n currentNode\[\"edtY\"].setVisible(True)\n #currentNode\[\"edtX\"].setValue(currentNode.width())\n #currentNode\[\"edtY\"].setValue(currentNode.height())\nelse:\n currentNode\[\"letterbox\"].setVisible(False)\n currentNode\[\"edtX\"].setVisible(False)\n currentNode\[\"edtY\"].setVisible(False)\n\n ratio = int(currentNode\[\"ddlLetterbox\"].value().split(\":\")\[0]) / int(currentNode\[\"ddlLetterbox\"].value().split(\":\")\[1])\n\n if (currentNode.width() / currentNode.height()) == ratio:\n currentNode\[\"edtX\"].setValue(currentNode.width())\n currentNode\[\"edtY\"].setValue(currentNode.height())\n\n elif (currentNode.width() / currentNode.height()) < ratio:\n currentNode\[\"edtX\"].setValue(currentNode.width())\n currentNode\[\"edtY\"].setValue(currentNode.width() / ratio)\n elif ratio == 1.0:\n currentNode\[\"edtX\"].setValue(currentNode.height())\n currentNode\[\"edtY\"].setValue(currentNode.height())\t\n else:\n currentNode\[\"edtX\"].setValue(currentNode.width() / ratio)\n currentNode\[\"edtY\"].setValue(currentNode.height() ) \n\n" 5 | addUserKnob {20 letterbox l Letterbox +HIDDEN} 6 | addUserKnob {52 knobChange l "" +STARTLINE T "nuke.thisNode().knob('knobChanged').setValue('''\n\ncurrentNode = nuke.thisNode()\n\n# THREADS\nif currentNode\[\"ddlLetterbox\"].value() == \"custom\":\n currentNode\[\"edtX\"].setVisible(True)\n currentNode\[\"edtY\"].setVisible(True)\n #currentNode\[\"edtX\"].setValue(currentNode.width())\n #currentNode\[\"edtY\"].setValue(currentNode.height())\nelse:\n currentNode\[\"letterbox\"].setVisible(False)\n currentNode\[\"edtX\"].setVisible(False)\n currentNode\[\"edtY\"].setVisible(False)\n\n ratio = int(currentNode\[\"ddlLetterbox\"].value().split(\":\")\[0]) / int(currentNode\[\"ddlLetterbox\"].value().split(\":\")\[1])\n\n if (currentNode.width() / currentNode.height()) == ratio:\n currentNode\[\"edtX\"].setValue(currentNode.width())\n currentNode\[\"edtY\"].setValue(currentNode.height())\n\n elif (currentNode.width() / currentNode.height()) < ratio:\n currentNode\[\"edtX\"].setValue(currentNode.width())\n currentNode\[\"edtY\"].setValue(currentNode.width() / ratio)\n elif ratio == 1.0:\n currentNode\[\"edtX\"].setValue(currentNode.height())\n currentNode\[\"edtY\"].setValue(currentNode.height())\t\n else:\n currentNode\[\"edtX\"].setValue(currentNode.width() / ratio)\n currentNode\[\"edtY\"].setValue(currentNode.height() ) \n\n''')" +STARTLINE} 7 | addUserKnob {26 lblLetterbox l Letterbox T ""} 8 | addUserKnob {6 cbxLetterbox l "" -STARTLINE} 9 | cbxLetterbox true 10 | addUserKnob {4 ddlLetterbox l " | " -STARTLINE M {1:1 4:3 14:9 16:9 21:9 custom "" "" "" "" ""}} 11 | ddlLetterbox 16:9 12 | addUserKnob {3 edtX l " | Resolution" -STARTLINE +HIDDEN} 13 | edtX 1920 14 | addUserKnob {3 edtY l "x " -STARTLINE +HIDDEN} 15 | edtY 1080 16 | addUserKnob {26 lblSpace04 l " | " -STARTLINE T ""} 17 | addUserKnob {6 chbReformat l Reformat -STARTLINE} 18 | addUserKnob {7 letterbox_opacity l Opacity} 19 | letterbox_opacity 1 20 | } 21 | Input { 22 | inputs 0 23 | name Input1 24 | xpos 0 25 | } 26 | Dot { 27 | name Dot1 28 | xpos 34 29 | ypos 91 30 | } 31 | set N8507bc00 [stack 0] 32 | Dot { 33 | name Dot2 34 | xpos 189 35 | ypos 91 36 | } 37 | set N8507b800 [stack 0] 38 | push $N8507bc00 39 | Crop { 40 | box {{"(input.width - parent.edtX) / 2" x113 0 x122 0} {"(input.height - parent.edtY) / 2" x122 0} {"parent.edtX + (input.width - parent.edtX) / 2" x113 1920 x122 1920} {"input.height - (input.height - parent.edtY) / 2" x113 1080 x122 1080}} 41 | reformat {{parent.chbReformat}} 42 | name crop 43 | selected true 44 | xpos 0 45 | ypos 172 46 | } 47 | set N8507b400 [stack 0] 48 | Merge2 { 49 | inputs 2 50 | mix {{"\[value parent.cbxLetterbox] ? 1 - parent.letterbox_opacity : 0" x113 0.585}} 51 | name Merge1 52 | xpos 155 53 | ypos 172 54 | } 55 | push $N8507b800 56 | Switch { 57 | inputs 2 58 | which {{parent.cbxLetterbox}} 59 | name Switch1 60 | xpos 265 61 | ypos 172 62 | } 63 | set N8507ac00 [stack 0] 64 | Output { 65 | name Output1 66 | xpos 265 67 | ypos 237 68 | } 69 | push $N8507b400 70 | push $N8507ac00 71 | Viewer { 72 | inputs 2 73 | frame_range 1-300 74 | name Viewer1 75 | xpos -322 76 | ypos 69 77 | } 78 | end_group 79 | -------------------------------------------------------------------------------- /software/nuke/init/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/nuke/init/__init__.py -------------------------------------------------------------------------------- /software/nuke/init/init.py: -------------------------------------------------------------------------------- 1 | # content = init Nuke 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import errno 9 | 10 | import nuke 11 | 12 | import plexfunc 13 | import plex 14 | 15 | 16 | # VARIABLE *************************************************************** 17 | LOG = plex.log(script=__name__) 18 | 19 | PROJECT_CONFIG = plex.config['project'] 20 | RESOLUTION = ' '.join([str(PROJECT_CONFIG['resolution'][0]), 21 | str(PROJECT_CONFIG['resolution'][1]), 22 | PROJECT_CONFIG['name'].replace(' ', '')]) 23 | 24 | 25 | def create_write_dir(): 26 | file_name = nuke.filename(nuke.thisNode()) 27 | file_path = os.path.dirname(file_name) 28 | os_path = nuke.callbacks.filenameFilter(file_path) 29 | 30 | # cope with the directory existing already by ignoring that exception 31 | try: 32 | os.makedirs(os_path) 33 | except OSError(e): 34 | if e.errno != errno.EEXIST: 35 | raise 36 | 37 | 38 | def add_plugin_paths(): 39 | # ADD all IMG paths 40 | for img in os.getenv('IMG_PATH').split(';'): 41 | for img_sub in plexfunc.get_sub_dirs(path=img, full_path=True): 42 | nuke.pluginAddPath(img_sub) 43 | 44 | # ADD sub software paths 45 | for path in os.getenv('SOFTWARE_PATH').split(';'): 46 | nuke.pluginAddPath(path) 47 | 48 | 49 | 50 | # PIPELINE *************************************************************** 51 | plex.init_software() 52 | add_plugin_paths() 53 | 54 | try: from scripts import write_node 55 | except: LOG.warning('FAILED loading write_node') 56 | 57 | # LOAD paths 58 | try: 59 | for paths in os.getenv('SOFTWARE_PATH').split(';'): 60 | nuke.pluginAddPath(paths) 61 | except: 62 | LOG.warning('FAILED loading SOFTWARE_PATH') 63 | 64 | 65 | 66 | print('SETTINGS') 67 | 68 | # RESOLUTIONs 69 | try: 70 | nuke.addFormat(RESOLUTION) 71 | nuke.knobDefault('Root.format', PROJECT_CONFIG['name'].replace(' ', '')) 72 | print(f' {chr(254)} ON - {RESOLUTION}') 73 | except: 74 | LOG.error(f' OFF - {RESOLUTION}', exc_info=True) 75 | print(f' {chr(254)} OFF - {RESOLUTION}') 76 | 77 | 78 | # FPS 79 | try: 80 | nuke.knobDefault("Root.fps", str(PROJECT_CONFIG['fps'])) 81 | print(f' {chr(254)} ON - {PROJECT_CONFIG['fps']} fps') 82 | except: 83 | LOG.error(f' OFF - {PROJECT_CONFIG['fps']} fps', exc_info=True) 84 | print(f' {chr(254)} OFF - {PROJECT_CONFIG['fps']} fps') 85 | 86 | 87 | # createFolder 88 | try: 89 | nuke.addBeforeRender(create_write_dir) 90 | print(f' {chr(254)} ON - create_write_dir (before render)') 91 | except: 92 | LOG.error(' OFF - create_write_dir (before render)', exc_info=True) 93 | print(f' {chr(254)} OFF - create_write_dir (before render)') 94 | 95 | print('') -------------------------------------------------------------------------------- /software/nuke/init/menu.py: -------------------------------------------------------------------------------- 1 | # 07 Week ********************************************************************* 2 | # content = menu Nuke 3 | # date = 03.12.2024 4 | # 5 | # license = MIT 6 | # author = Alexander Richter 7 | 8 | import os 9 | import nuke 10 | import importlib 11 | 12 | import plex 13 | 14 | LOG = plex.log(script=__name__) 15 | 16 | 17 | def add_gizmo_menu(menu): 18 | for paths in os.getenv('SOFTWARE_PATH').split(';'): 19 | for file in os.listdir(paths): 20 | if file.endswith('.gizmo'): 21 | gizmo = file.replace('.gizmo', '') 22 | menu.addCommand('Gizmos/' + gizmo, f'nuke.tcl("{gizmo}")') 23 | 24 | def add_write_node(): 25 | import write_node 26 | for node in nuke.allNodes('arWrite'): 27 | write_node.create_node(node) 28 | 29 | 30 | # TOOLBAR *************************************************************** 31 | menu_config = plex.config['software']['MENU'] 32 | menuNode = nuke.menu('Nodes').addMenu(plex.config['project']['name'], icon = 'nuke.ico') 33 | 34 | nuke.addOnScriptSave(add_write_node) 35 | 36 | # ADD menu 37 | plex.software.add_menu(menuNode) 38 | menuNode.addSeparator() 39 | add_gizmo_menu(menuNode) 40 | 41 | 42 | # ACTIONS *************************************************************** 43 | def save(): 44 | import arSave 45 | arSave.start() 46 | 47 | 48 | def load(): 49 | import arLoad 50 | arLoad.start() 51 | 52 | 53 | def arWrite(): 54 | importlib.reload(write_node) 55 | nuke.createNode('arWrite') 56 | -------------------------------------------------------------------------------- /software/nuke/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/nuke/plugins/__init__.py -------------------------------------------------------------------------------- /software/nuke/scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexanderrichtertd/plex/ad2af223fbbfd54d486ca6e42587e0dfaf342226/software/nuke/scripts/__init__.py -------------------------------------------------------------------------------- /software/nuke/scripts/nuke_dcc.py: -------------------------------------------------------------------------------- 1 | # content = Nuke 2 | # date = 03.12.2024 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | 9 | import nuke 10 | 11 | import plex 12 | from software import Software 13 | 14 | 15 | # VARIABLE *************************************************************** 16 | LOG = plex.log(script=__name__) 17 | DEFAULT_PATH = os.path.normpath(plex.get_config('config_user') + '/tmp_img.jpg') 18 | 19 | 20 | class Nuke(Software): 21 | 22 | _NAME = 'nuke' 23 | 24 | @property 25 | def scene_path(self): 26 | return nuke.root().knob('name').value() 27 | 28 | def scene_save(self): 29 | return nuke.scriptSave() 30 | 31 | def scene_save_as(self, file, setup_scene=False): 32 | nuke.scriptSaveAs(file) 33 | 34 | def scene_open(self, file): 35 | return nuke.scriptOpen(file) 36 | 37 | def scene_import(self, file): 38 | pass 39 | 40 | 41 | # SNAPSHOT *************************************************************** 42 | def viewport_snapshot(img_path=DEFAULT_PATH): 43 | viewer = nuke.activeViewer() 44 | viewNode = nuke.activeViewer().node() 45 | 46 | actInput = nuke.ViewerWindow.activeInput(viewer) 47 | if actInput < 0: return False 48 | 49 | selInput = nuke.Node.input(viewNode, actInput) 50 | 51 | # look up filename based on top read node 52 | topName ="[file tail [knob [topnode].file]]" 53 | 54 | # create writes and define render format 55 | write1 = nuke.nodes.Write( file=img_path.replace("\\", "/"), name='writeNode1' , file_type=plex.config['project']['EXTENSION']['thumnail']) 56 | write1.setInput(0, selInput) 57 | 58 | # look up current frame 59 | curFrame = int(nuke.knob("frame")) 60 | # start the render 61 | nuke.execute( write1.name(), curFrame, curFrame ) 62 | # clean up 63 | for n in [write1]: nuke.delete(n) 64 | 65 | LOG.info("nuke_viewer_snapshot") 66 | -------------------------------------------------------------------------------- /software/nuke/scripts/write_node.py: -------------------------------------------------------------------------------- 1 | # content = write node functions 2 | # date = 2020-06-19 3 | # 4 | # license = MIT 5 | # author = Alexander Richter 6 | 7 | import os 8 | import shutil 9 | 10 | import webbrowser 11 | 12 | import nuke 13 | 14 | import arNotice 15 | import plex 16 | 17 | LOG = plex.log(script=__name__) 18 | 19 | 20 | # INIT *************************************************************** 21 | def create_node(this_node=''): 22 | if not this_node: this_node = nuke.thisNode() 23 | 24 | if this_node["customRange"].getValue(): 25 | this_node["frameStart"].setValue(int(nuke.Root()['first_frame'].getValue())) 26 | this_node["frameEnd"].setValue(int(nuke.Root()['last_frame'].getValue())) 27 | 28 | this_node["resolutionX"].setValue(this_node.width()) 29 | this_node["resolutionY"].setValue(this_node.height()) 30 | 31 | fileName = os.path.basename(nuke.root().name()).split(".")[0] 32 | renderPath = f"{os.path.dirname(os.path.dirname(nuke.root().name()))}/RENDER/{fileName}/exr/{fileName}.%04d.exr" 33 | renderPath = renderPath.replace('\\','/') 34 | 35 | # this_node["rootPath"].setValue(renderPath) 36 | this_node["exrPath"].setValue(renderPath) 37 | this_node["jpgPath"].setValue(renderPath.replace("exr","jpg")) 38 | this_node["tifPath"].setValue(renderPath.replace("exr","tif")) 39 | 40 | 41 | def openRV(path): 42 | if not os.path.exists(os.path.dirname(path)) or not os.listdir(os.path.dirname(path)): 43 | LOG.warning("FOLDER : NOT EXISTS : " + path) 44 | else: 45 | os.system('start "" "' + plex.config['software']['RV']['path'] + '" ' + path) 46 | 47 | 48 | # TODO: REPLACE with lib.plex.openFolder(path) 49 | def openFolder(path): 50 | path = os.path.dirname(path).replace("/","\\") 51 | if not os.path.exists(path) or not os.listdir(path): 52 | LOG.warning("FOLDER : NOT EXISTS : " + path) 53 | else: 54 | webbrowser.open(path) 55 | 56 | 57 | def render(): 58 | this_node = nuke.thisNode() 59 | 60 | frameStart = int(this_node["frameStart"].getValue()) 61 | frameEnd = int(this_node["frameEnd"].getValue()) 62 | 63 | LOG.info(f'{frameStart}-{frameEnd}') 64 | 65 | notice_status = {'RENDERTHREADS': 'multi process rendering is started', 66 | 'RR SUBMIT': 'scene was submit to RR', 67 | 'LOCAL': 'local rendering was started', 68 | 'NO JOB': 'process seems to be broken'} 69 | 70 | tmp_job = 'NO JOB' 71 | 72 | # RENDERTHREADS 73 | if this_node["submit"].getValue() == 0.0: 74 | from plugins.vuRenderThreads.plugin_nuke import plugin_nuke 75 | threads = int(this_node["threads"].getValue()) 76 | plugin_nuke.createThreads(frameStart, frameEnd, threads, [this_node.name()]) 77 | LOG.info("END : RENDERTHREADS : " + this_node["exrPath"].getValue()) 78 | tmp_job = 'RENDERTHREADS' 79 | 80 | # RENDERFARM 81 | elif this_node["submit"].getValue() == 1.0: 82 | import rrenderSubmit 83 | nuke.load('rrenderSubmit') 84 | rrenderSubmit.rrSubmit_Nuke_Node(this_node, frameStart, frameEnd) 85 | LOG.info("END : RRSUBMIT : " + this_node["exrPath"].getValue()) 86 | tmp_job = 'RR SUBMIT' 87 | 88 | # LOCAL 89 | else: 90 | try: 91 | nuke.execute(nuke.thisNode(), start=frameStart, end=frameEnd, incr=1) 92 | tmp_job = 'LOCAL' 93 | except: LOG.error("END : LOCAL : " + this_node["exrPath"].getValue(), exc_info=True) 94 | 95 | arNotice.ArNotice(title = os.path.basename(nuke.root().name()).split('.')[0], 96 | msg = notice_status[tmp_job], 97 | func = tmp_job, 98 | img = 'lbl/lblNuke131' if tmp_job!='NO JOB' else 'lbl/lblWarning131', 99 | img_link = '') 100 | 101 | 102 | def publishRender(file_type): 103 | this_node = nuke.thisGroup() 104 | if not this_node["chbPublish"].value(): return 105 | 106 | fileName = [] 107 | splitFile = os.path.basename(nuke.root().name()).split(".")[0].split("_") 108 | 109 | for part in splitFile: 110 | fileName.append(part) 111 | if part == 'COMP': break 112 | 113 | fileName = "_".join(fileName) 114 | publishPath = f'{os.path.dirname(os.path.dirname(nuke.root().name()))}/{plex.config['plex']['publish']}/{file_type}' 115 | oldPath = os.path.dirname(this_node[file_type + "Path"].getValue()) 116 | 117 | LOG.info("PUBLISH: " + publishPath) 118 | 119 | if not os.path.exists(publishPath): os.makedirs(publishPath) 120 | 121 | oldFrames = plex.getFolderList(oldPath, fileType='*' + file_type, ex=True) 122 | 123 | for oldFrame in oldFrames: 124 | framePart = oldFrame.split(".") 125 | framePart[0] = fileName 126 | 127 | newFrame = publishPath + "/" + ".".join(framePart) 128 | oldFrame = oldPath + "/" + oldFrame 129 | 130 | shutil.copyfile(oldFrame, newFrame) 131 | --------------------------------------------------------------------------------