L
Oh, I know exactly what you are looking for. I got it:In the old f95 thread, the one that got deleted, there was a script someone made that scanned desired folders for timeline scenes and you could even filter by length. Does anyone have it still? It was a python script, an updated version of Shallty's.
import ctypes
import glob
import os
import shutil
os.system('cls' if os.name == 'nt' else 'clear')
print("")
print("")
ctypes.windll.kernel32.SetConsoleTitleW("TIMELINE CHECKER")
input_path = 'C:/.../UserData/Studio/scene/folderIn'
output_path = 'C:/.../UserData/Studio/scene/folderOut'
timeline_length = 2.0
if not os.path.exists(output_path):
os.makedirs(output_path)
print(f"\nSearching .png files...\n")
files = glob.glob(input_path + '/**/*.png', recursive=True)
total_files = len(files)
print(f"\n({total_files}) .png files founded.\n")
count = 0
tl_count = 0
check_list = ['cameraOPos"', 'cameraORot"', 'cameraOZoom"', 'cameraFOV"', 'cameraPos"', 'cameraRot"', 'timeScale"']
for current_file in files:
has_time_greater_than_value = False
if os.path.isfile(current_file):
with open(current_file, 'rt', encoding="ansi") as fp:
for index, line in enumerate(fp):
if line.count("Timeline") >= 2:
if 'timeline' in line:
elements = line.strip().split()
for element in elements:
if 'time="' in element:
try:
time_value = float(element.split('time="')[1].replace('"', ''))
if time_value > timeline_length:
has_time_greater_than_value = True
except ValueError:
continue
if has_time_greater_than_value and 'id="' in element and not any(
check_string in element for check_string in check_list):
tl_count += 1
file_name = os.path.split(current_file)
print('\nTimeline scene found: ' + file_name[1] + '\n')
fp.close()
shutil.move(current_file, output_path + '\\' + file_name[1])
break
else:
continue
break
else:
fp.close()
count += 1
print(f"\n({count}/{total_files}) Timeline scene count: [{tl_count}]\n")
print("\n╭⋟────────────────────────────────────────────────────────────────╮")
print(f'\n Total timeline scenes found: [{tl_count}/{total_files}]\n')
print("╰────────────────────────────────────────────────────────────────⋞╯\n\n") THANK YOU SO MUCH I THOUGHT IT WAS LOST MEDIAOh, I know exactly what you are looking for. I got it:
Python:import ctypes import glob import os import shutil os.system('cls' if os.name == 'nt' else 'clear') print("") print("") ctypes.windll.kernel32.SetConsoleTitleW("TIMELINE CHECKER") input_path = 'C:/.../UserData/Studio/scene/folderIn' output_path = 'C:/.../UserData/Studio/scene/folderOut' timeline_length = 2.0 if not os.path.exists(output_path): os.makedirs(output_path) print(f"\nSearching .png files...\n") files = glob.glob(input_path + '/**/*.png', recursive=True) total_files = len(files) print(f"\n({total_files}) .png files founded.\n") count = 0 tl_count = 0 check_list = ['cameraOPos"', 'cameraORot"', 'cameraOZoom"', 'cameraFOV"', 'cameraPos"', 'cameraRot"', 'timeScale"'] for current_file in files: has_time_greater_than_value = False if os.path.isfile(current_file): with open(current_file, 'rt', encoding="ansi") as fp: for index, line in enumerate(fp): if line.count("Timeline") >= 2: if 'timeline' in line: elements = line.strip().split() for element in elements: if 'time="' in element: try: time_value = float(element.split('time="')[1].replace('"', '')) if time_value > timeline_length: has_time_greater_than_value = True except ValueError: continue if has_time_greater_than_value and 'id="' in element and not any( check_string in element for check_string in check_list): tl_count += 1 file_name = os.path.split(current_file) print('\nTimeline scene found: ' + file_name[1] + '\n') fp.close() shutil.move(current_file, output_path + '\\' + file_name[1]) break else: continue break else: fp.close() count += 1 print(f"\n({count}/{total_files}) Timeline scene count: [{tl_count}]\n") print("\n╭⋟────────────────────────────────────────────────────────────────╮") print(f'\n Total timeline scenes found: [{tl_count}/{total_files}]\n') print("╰────────────────────────────────────────────────────────────────⋞╯\n\n")
Yes. The above one seems to have problems when I run it. I found another one.btw what does it do? identify the non timeline vs timeline scene?
import os
import shutil
class TimelineDetector:
"""
The functionality of this class is identical to the original code you provided.
It is responsible for analyzing the content of a single file to determine its type.
"""
def __init__(self, file_path: str = None):
self.file_path = file_path
def is_scene_data(self, content_str: str) -> bool:
"""Checks if the content is scene data."""
return "KStudio" in content_str
def check_timeline(self, content_str: str) -> tuple[str, str, float]:
"""
Checks the timeline type and returns the timeline status and duration.
Returns:
tuple (timeline_status, image_type, duration)
timeline_status: "has_timeline" or "no_timeline"
image_type: "dynamic", "static", or None
duration: float or None
"""
if "timeline" in content_str: # First, check if "timeline" exists
# Check if it's static (it's static if "Timeline" is not present)
if "Timeline" not in content_str:
return "has_timeline", "static", None
else:
# It's dynamic, now check for duration
if "duration" in content_str:
dur_pos = content_str.find("duration")
search_pos = dur_pos + len("duration")
while search_pos < len(content_str):
if content_str[search_pos].isdigit():
num_start = search_pos
num_end = num_start
while num_end < len(content_str) and (content_str[num_end].isdigit() or content_str[num_end] == '.'):
num_end += 1
try:
duration = float(content_str[num_start:num_end])
return "has_timeline", "dynamic", duration
except ValueError:
return "has_timeline", "dynamic", None
search_pos += 1
return "has_timeline", "dynamic", None
return "no_timeline", None, None
def batch_process_animated_images(input_dir: str, output_dir: str):
"""
Iterates through the input directory, finds all dynamic images,
and moves them to the output directory.
Args:
input_dir (str): The path to the source folder containing .png files.
output_dir (str): The path to the destination folder for dynamic images.
"""
# Ensure the output directory exists, create it if it doesn't
if not os.path.exists(output_dir):
os.makedirs(output_dir)
print(f"Created output directory: {output_dir}")
detector = TimelineDetector()
animated_image_count = 0
print(f"Starting scan of input directory: {input_dir}")
print("Operation Mode: Move Files")
# Iterate over all files in the input directory
for filename in os.listdir(input_dir):
# Only process .png files
if filename.lower().endswith(".png"):
file_path = os.path.join(input_dir, filename)
# Skip subdirectories, process only files
if not os.path.isfile(file_path):
continue
try:
with open(file_path, 'rb') as f:
content = f.read()
content_str = content.decode('utf-8', errors='ignore')
# 1. Check if it's valid scene data
if not detector.is_scene_data(content_str):
print(f"Skipped (not scene data): {filename}")
continue
# 2. Check the timeline status
timeline_status, image_type, duration = detector.check_timeline(content_str)
# 3. If it's a dynamic image with a timeline, move it
if timeline_status == "has_timeline" and image_type == "dynamic":
destination_path = os.path.join(output_dir, filename)
# Use shutil.move to move the file
shutil.move(file_path, destination_path)
duration_info = f" (duration: {duration}s)" if duration is not None else ""
print(f"Found dynamic image, moved: {filename}{duration_info}")
animated_image_count += 1
else:
print(f"Skipped (not a dynamic image): {filename}")
except Exception as e:
print(f"Error processing file {filename}: {e}")
print("\nBatch processing complete.")
print(f"Total files moved: {animated_image_count} dynamic images to {output_dir}")
def main():
# ==================================================================
# === Please configure your paths here ===
# ==================================================================
# Replace "Please_paste_your_full_input_directory_path_here" with the path to the folder containing your .png files.
# Example (Windows): "C:\\Users\\YourUser\\Desktop\\input"
# Example (macOS): "/Users/YourUser/Desktop/input"
INPUT_DIRECTORY = "Please_paste_your_full_input_directory_path_here"
# Replace "Please_paste_your_full_output_directory_path_here" with the path to the folder where you want to store the dynamic images.
# Example (Windows): "C:\\Users\\YourUser\\Desktop\\output_animated"
# Example (macOS): "/Users/YourUser/Desktop/output_animated"
OUTPUT_DIRECTORY = "Please_paste_your_full_output_directory_path_here"
# ==================================================================
# === End of configuration. Please do not modify below this line. ===
# ==================================================================
# Check if the paths have been set
if "Please_paste" in INPUT_DIRECTORY or "Please_paste" in OUTPUT_DIRECTORY:
print("Error: You have not configured the input or output directory paths.")
print("Please open this .py file with a text editor and fill in the values for INPUT_DIRECTORY and OUTPUT_DIRECTORY.")
input("\nPress Enter to exit...")
return
# Check if the input path exists and is a directory
if not os.path.isdir(INPUT_DIRECTORY):
print(f"Error: The input path '{INPUT_DIRECTORY}' is not a valid directory.")
input("\nPress Enter to exit...")
return
# Check if the input and output paths are the same
if os.path.abspath(INPUT_DIRECTORY) == os.path.abspath(OUTPUT_DIRECTORY):
print(f"Error: The input and output directories cannot be the same path.")
input("\nPress Enter to exit...")
return
# Execute the batch process
batch_process_animated_images(INPUT_DIRECTORY, OUTPUT_DIRECTORY)
input("\nAll tasks are complete. Press Enter to exit...")
if __name__ == "__main__":
main() If you have trouble getting the first script to work, it was probably because the script uses \ and not / sometimes. Dunno why.Yes. The above one seems to have problems when I run it. I found another one.
Python:import os import shutil class TimelineDetector: """ The functionality of this class is identical to the original code you provided. It is responsible for analyzing the content of a single file to determine its type. """ def __init__(self, file_path: str = None): self.file_path = file_path def is_scene_data(self, content_str: str) -> bool: """Checks if the content is scene data.""" return "KStudio" in content_str def check_timeline(self, content_str: str) -> tuple[str, str, float]: """ Checks the timeline type and returns the timeline status and duration. Returns: tuple (timeline_status, image_type, duration) timeline_status: "has_timeline" or "no_timeline" image_type: "dynamic", "static", or None duration: float or None """ if "timeline" in content_str: # First, check if "timeline" exists # Check if it's static (it's static if "Timeline" is not present) if "Timeline" not in content_str: return "has_timeline", "static", None else: # It's dynamic, now check for duration if "duration" in content_str: dur_pos = content_str.find("duration") search_pos = dur_pos + len("duration") while search_pos < len(content_str): if content_str[search_pos].isdigit(): num_start = search_pos num_end = num_start while num_end < len(content_str) and (content_str[num_end].isdigit() or content_str[num_end] == '.'): num_end += 1 try: duration = float(content_str[num_start:num_end]) return "has_timeline", "dynamic", duration except ValueError: return "has_timeline", "dynamic", None search_pos += 1 return "has_timeline", "dynamic", None return "no_timeline", None, None def batch_process_animated_images(input_dir: str, output_dir: str): """ Iterates through the input directory, finds all dynamic images, and moves them to the output directory. Args: input_dir (str): The path to the source folder containing .png files. output_dir (str): The path to the destination folder for dynamic images. """ # Ensure the output directory exists, create it if it doesn't if not os.path.exists(output_dir): os.makedirs(output_dir) print(f"Created output directory: {output_dir}") detector = TimelineDetector() animated_image_count = 0 print(f"Starting scan of input directory: {input_dir}") print("Operation Mode: Move Files") # Iterate over all files in the input directory for filename in os.listdir(input_dir): # Only process .png files if filename.lower().endswith(".png"): file_path = os.path.join(input_dir, filename) # Skip subdirectories, process only files if not os.path.isfile(file_path): continue try: with open(file_path, 'rb') as f: content = f.read() content_str = content.decode('utf-8', errors='ignore') # 1. Check if it's valid scene data if not detector.is_scene_data(content_str): print(f"Skipped (not scene data): {filename}") continue # 2. Check the timeline status timeline_status, image_type, duration = detector.check_timeline(content_str) # 3. If it's a dynamic image with a timeline, move it if timeline_status == "has_timeline" and image_type == "dynamic": destination_path = os.path.join(output_dir, filename) # Use shutil.move to move the file shutil.move(file_path, destination_path) duration_info = f" (duration: {duration}s)" if duration is not None else "" print(f"Found dynamic image, moved: {filename}{duration_info}") animated_image_count += 1 else: print(f"Skipped (not a dynamic image): {filename}") except Exception as e: print(f"Error processing file {filename}: {e}") print("\nBatch processing complete.") print(f"Total files moved: {animated_image_count} dynamic images to {output_dir}") def main(): # ================================================================== # === Please configure your paths here === # ================================================================== # Replace "Please_paste_your_full_input_directory_path_here" with the path to the folder containing your .png files. # Example (Windows): "C:\\Users\\YourUser\\Desktop\\input" # Example (macOS): "/Users/YourUser/Desktop/input" INPUT_DIRECTORY = "Please_paste_your_full_input_directory_path_here" # Replace "Please_paste_your_full_output_directory_path_here" with the path to the folder where you want to store the dynamic images. # Example (Windows): "C:\\Users\\YourUser\\Desktop\\output_animated" # Example (macOS): "/Users/YourUser/Desktop/output_animated" OUTPUT_DIRECTORY = "Please_paste_your_full_output_directory_path_here" # ================================================================== # === End of configuration. Please do not modify below this line. === # ================================================================== # Check if the paths have been set if "Please_paste" in INPUT_DIRECTORY or "Please_paste" in OUTPUT_DIRECTORY: print("Error: You have not configured the input or output directory paths.") print("Please open this .py file with a text editor and fill in the values for INPUT_DIRECTORY and OUTPUT_DIRECTORY.") input("\nPress Enter to exit...") return # Check if the input path exists and is a directory if not os.path.isdir(INPUT_DIRECTORY): print(f"Error: The input path '{INPUT_DIRECTORY}' is not a valid directory.") input("\nPress Enter to exit...") return # Check if the input and output paths are the same if os.path.abspath(INPUT_DIRECTORY) == os.path.abspath(OUTPUT_DIRECTORY): print(f"Error: The input and output directories cannot be the same path.") input("\nPress Enter to exit...") return # Execute the batch process batch_process_animated_images(INPUT_DIRECTORY, OUTPUT_DIRECTORY) input("\nAll tasks are complete. Press Enter to exit...") if __name__ == "__main__": main()