/
Manifest
/
Real_Texture
Обзор
Документация
Войти
/
Manifest
/
Real_Texture
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
ToolsPythonForSequenceInUE/DeleteCadr.py
248 строк
8 KB
m.samodurov
init commit for The Invaders
17 фев 2026, 04:57
17 фев 2026, 04:57
4a668d4
Код
Авторство
О чём код?
import os import re # ------------------------- # Универсальная функция: определяет диапазон кадров для любого расширения # ------------------------- def get_range(directory: str, prefix: str, ext: str): """ Scans directory for files that match pattern: <prefix>.<frame>.<ext> Returns (min_frame, max_frame, padding) """ if not os.path.isdir(directory): raise RuntimeError(f"Directory does not exist: {directory}") pattern = re.compile(r'^' + re.escape(prefix) + r'[._](\d+)\.' + re.escape(ext) + r'$', re.IGNORECASE) frames = [] paddings = set() for f in os.listdir(directory): m = pattern.match(f) if m: frame_str = m.group(1) frames.append(int(frame_str)) paddings.add(len(frame_str)) if not frames: raise RuntimeError(f"No {ext.upper()} files found for prefix '{prefix}' in {directory}") return min(frames), max(frames), max(paddings) # ------------------------- # Универсальное смещение (EXR или PNG) # ------------------------- def shift_and_rename(directory: str, prefix: str, start_frame: int, end_frame: int, padding: int, ext: str): def fname(frame): return f"{prefix}.{frame:0{padding}d}.{ext}" first_file = os.path.join(directory, fname(start_frame)) if os.path.exists(first_file): os.remove(first_file) print(f"Deleted: {first_file}") else: print(f"First file not found: {first_file}") # Shift remaining files for frame in range(start_frame + 1, end_frame + 1): src = os.path.join(directory, fname(frame)) dst = os.path.join(directory, fname(frame - 1)) if not os.path.exists(src): print(f"Source not found (skip): {src}") continue os.rename(src, dst) print(f"Renamed {src} → {dst}") print(f"Shift complete for *.{ext}") # ------------------------- # Запуск # ------------------------- if __name__ == "__main__": DIRECTORY = r"C:\Manifest\ep008_sq010_sh0040.v009" PREFIX = "ep008_sq010_sh0040.v001" for ext in ("exr", "png"): try: start, end, padding = get_range(DIRECTORY, PREFIX, ext) shift_and_rename(DIRECTORY, PREFIX, start, end, padding, ext) except Exception as e: print(f"[{ext.upper()}] {e}") import os import re # ------------------------- # UE / non-UE logging # ------------------------- try: import unreal def log(msg): unreal.log(str(msg)) def log_warn(msg): unreal.log_warning(str(msg)) def log_err(msg): unreal.log_error(str(msg)) except Exception: def log(msg): print(msg) def log_warn(msg): print("WARN:", msg) def log_err(msg): print("ERROR:", msg) # ------------------------- # Read inputs from Python Script Executor pins (case-insensitive) # ------------------------- def _get_global_ci(name: str): """Get globals()[key] ignoring case. Returns None if not found.""" target = name.lower() g = globals() for k, v in g.items(): if isinstance(k, str) and k.lower() == target: return v return None def read_inputs(): versions_root = _get_global_ci("VERSIONS_ROOT") folder_base = _get_global_ci("FOLDER_BASE") prefix_base = _get_global_ci("PREFIX_BASE") # accept your lowercase pin names too if versions_root is None: versions_root = _get_global_ci("versions_root") if folder_base is None: folder_base = _get_global_ci("folder_base") if prefix_base is None: prefix_base = _get_global_ci("prefix_base") if versions_root is None: # полезно для отладки: покажем похожие глобалы keys = [k for k in globals().keys() if isinstance(k, str) and ("root" in k.lower() or "folder" in k.lower() or "prefix" in k.lower())] raise RuntimeError(f"Missing input pin: versions_root (or VERSIONS_ROOT). Similar globals: {keys}") if folder_base is None: raise RuntimeError("Missing input pin: folder_base (or FOLDER_BASE)") if prefix_base is None: raise RuntimeError("Missing input pin: prefix_base (or PREFIX_BASE)") versions_root = str(versions_root).strip().strip('"').strip("'") folder_base = str(folder_base).strip().strip('"').strip("'") prefix_base = str(prefix_base).strip().strip('"').strip("'") if not versions_root: raise RuntimeError("Input versions_root is empty") if not folder_base: raise RuntimeError("Input folder_base is empty") if not prefix_base: raise RuntimeError("Input prefix_base is empty") versions_root = os.path.normpath(versions_root) if not os.path.isdir(versions_root): raise RuntimeError(f"versions_root does not exist: {versions_root}") folder_base = folder_base.rstrip(".") prefix_base = prefix_base.rstrip(".") return versions_root, folder_base, prefix_base # ------------------------- # Find latest version folder: <folder_base>.v### # ------------------------- def find_latest_version(versions_root: str, folder_base: str): pat = re.compile(rf"^{re.escape(folder_base)}\.v(?P<num>\d+)$", re.IGNORECASE) candidates = [] for name in os.listdir(versions_root): full = os.path.join(versions_root, name) if not os.path.isdir(full): continue m = pat.match(name) if not m: continue digits = m.group("num") candidates.append((int(digits), digits, full)) if not candidates: raise RuntimeError( f"No version folders found in:\n {versions_root}\n" f"Expected: {folder_base}.v###" ) candidates.sort(key=lambda x: x[0], reverse=True) _, digits, best_dir = candidates[0] return best_dir, f"v{digits}" # ------------------------- # Detect frame range for ext # ------------------------- def get_range(directory: str, prefix: str, ext: str): prefix = prefix.rstrip(".") pattern = re.compile( r'^' + re.escape(prefix) + r'[._](\d+)\.' + re.escape(ext) + r'$', re.IGNORECASE ) frames = [] paddings = set() for f in os.listdir(directory): m = pattern.match(f) if m: s = m.group(1) frames.append(int(s)) paddings.add(len(s)) if not frames: raise RuntimeError(f"No {ext.upper()} files found for prefix '{prefix}' in {directory}") return min(frames), max(frames), max(paddings) # ------------------------- # Delete first frame, shift remaining by -1 # ------------------------- def shift_and_rename(directory: str, prefix: str, start_frame: int, end_frame: int, padding: int, ext: str): prefix = prefix.rstrip(".") def fname(frame: int) -> str: return f"{prefix}.{frame:0{padding}d}.{ext}" first_file = os.path.join(directory, fname(start_frame)) if os.path.exists(first_file): os.remove(first_file) log(f"Deleted: {first_file}") else: log_warn(f"First file not found: {first_file}") for frame in range(start_frame + 1, end_frame + 1): src = os.path.join(directory, fname(frame)) dst = os.path.join(directory, fname(frame - 1)) if not os.path.exists(src): log_warn(f"Source not found (skip): {src}") continue os.rename(src, dst) log(f"Renamed {src} -> {dst}") log(f"Shift complete for *.{ext}") # ------------------------- # EXECUTE # ------------------------- try: versions_root, folder_base, prefix_base = read_inputs() resolved_dir, version_str = find_latest_version(versions_root, folder_base) full_prefix = f"{prefix_base}.{version_str}" # prefix_base already without trailing dot log(f"Resolved directory: {resolved_dir}") log(f"Resolved prefix: {full_prefix}") for ext in ("exr", "png"): try: start, end, padding = get_range(resolved_dir, full_prefix, ext) shift_and_rename(resolved_dir, full_prefix, start, end, padding, ext) except Exception as e: log_warn(f"[{ext.upper()}] {e}") except Exception as e: log_err(e) raise