gp_render/OP_post_render.py

167 lines
5.5 KiB
Python
Raw Normal View History

import bpy
import os
from pathlib import Path
import re
from time import time
def renumber_sequence_on_disk_from_file_slots(apply=True, active_scene_only=False):
'''renumber sequence on disk from scenes file slots'''
scn = bpy.context.scene
blend = Path(bpy.data.filepath)
render = blend.parent / 'render'
prenum = re.compile(r'\d{3}_')
print('-- starting rename sequences numbers from fileslots number')
if not apply:
print('-- Dry run')
t0 = time()
ct = 0
if active_scene_only:
# Only on currrent scene
file_outs = [n for n in bpy.context.scene.node_tree.nodes if n.type == 'OUTPUT_FILE' and n.name.startswith('OUT_') and not n.mute]
else:
# multi scene check:
file_outs = []
for S in bpy.data.scenes:
2024-04-22 15:39:40 +02:00
if not S.node_tree or not S.use_nodes: # S.name == 'Scene' or
continue
file_outs += [n for n in S.node_tree.nodes if n.type == 'OUTPUT_FILE' and n.name.startswith('OUT_') and not n.mute]
if not file_outs:
return 'No file output found (should be unmuted nodes with name starting with OUT_)', '_'
for fo in file_outs:
obj_full = fo.base_path.split('/')[-1]
obj = prenum.sub('', obj_full)
obj_num = prenum.search(obj_full)
if obj_num:
obj_num = obj_num.group(0)
2023-01-18 14:28:27 +01:00
## check if folder exists
folder_path = None
2023-01-18 14:28:27 +01:00
for d in os.scandir(render):
if d.is_dir() and prenum.sub('', d.name) == obj:
folder_path = render / d.name
break
2023-01-18 14:28:27 +01:00
if not folder_path:
print(f'Could not find obj folder for: {obj}')
continue
# rename inside folder dirst so that root path isn't changed while iterating
for fs in fo.file_slots:
img_full = fs.path.split('/')[0]
img = prenum.sub('', img_full)
img_num = prenum.search(img_full)
if img_num:
img_num = img_num.group(0)
else:
print(f'! no num : {fo.base_path} : {img_full}')
continue # If no img_num no point in renaming sequences
img_dir_path = None
2023-01-18 14:28:27 +01:00
for img_dir in os.scandir(folder_path):
if img_dir.is_dir() and prenum.sub('', img_dir.name) == img:
img_dir_path = folder_path / img_dir.name
break
2023-01-18 14:28:27 +01:00
if not img_dir_path:
print(f'Could not find img folder for: {img}')
continue
2023-01-18 14:28:27 +01:00
# if folder exists check if full name is ok
if img_full == img_dir_path.name:
continue # name already (maybe not in sequence but should be good)
2023-01-18 14:28:27 +01:00
# rename sequence and image folder
for frame in os.scandir(img_dir_path):
good = img_num + prenum.sub('', frame.name)
if frame.name != good:
print(f' img: {frame.name} > {good}')
ct += 1
if apply:
fp = Path(frame.path)
fp.rename(fp.parent / good)
2023-01-18 14:28:27 +01:00
# rename image folder
if img_dir_path.name != img_full:
print(f' dir:{img_dir_path.name} > {img_full}')
ct += 1
if apply:
img_dir_path.rename(img_dir_path.parent / img_full)
# rename object folder
if obj_num and folder_path.name != obj_full:
print(f'obj: {folder_path.name} > {obj_full}')
ct += 1
if apply:
folder_path.rename(folder_path.parent / obj_full)
elapsed = f'{time() - t0:.2f}s'
print(f'Eslapsed time: {elapsed}')
return ct, elapsed
class GPEXP_OT_renumber_files_on_disk(bpy.types.Operator):
bl_idname = "gp.renumber_files_on_disk"
bl_label = "Renumber Files On Disk"
bl_description = "Rename folder/files in render folder on disk according to unmuted file output numbering"
bl_options = {"REGISTER"}
def invoke(self, context, event):
# return self.execute(context)
return context.window_manager.invoke_props_dialog(self)
2023-01-18 14:28:27 +01:00
dry_run: bpy.props.BoolProperty(name='Dry-run (no actions, prints in console only)',
default=False,
description='Test mode. If checked, no action is actually performed')
2023-01-18 14:28:27 +01:00
active_scene_only: bpy.props.BoolProperty(name='Only Active Scene',
default=False,
description='use only file output of active scene instead of all scenes (skipping "Scene")')
def draw(self, context):
layout = self.layout
layout.prop(self, 'dry_run')
layout.prop(self, 'active_scene_only')
def execute(self, context):
ct, timing = renumber_sequence_on_disk_from_file_slots(apply = not self.dry_run, active_scene_only=self.active_scene_only)
if isinstance(ct, str):
self.report({'ERROR'}, ct)
return {"CANCELLED"}
if not ct:
self.report({'WARNING'}, 'Already good or nothing to rename')
return {"CANCELLED"}
if self.dry_run:
mess = f'Dry run : {ct} items would have been renamed, see console'
else:
mess = f'{ct} items renamed in {timing}'
self.report({'INFO'}, mess)
return {"FINISHED"}
classes=(
GPEXP_OT_renumber_files_on_disk,
)
2023-01-18 14:28:27 +01:00
def register():
for cls in classes:
bpy.utils.register_class(cls)
def unregister():
for cls in reversed(classes):
bpy.utils.unregister_class(cls)