Last active
October 20, 2025 19:16
-
-
Save plyrthn/6f4893040e023d6f1e67efd4663a0582 to your computer and use it in GitHub Desktop.
Fixes corrupted Steam game recording timeline files that prevent clips from being saved or exported on steam game recording.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import json | |
| import os | |
| import shutil | |
| ## Credit for finding this solution go to: | |
| ## https://steamcommunity.com/groups/SteamClientBeta/discussions/0/601916204203051690/ | |
| ## https://steamcommunity.com/groups/SteamClientBeta/discussions/5/601917463282777291/#c601917691382761871 | |
| def fix_timeline_file(filepath): | |
| try: | |
| with open(filepath, 'r', encoding='utf-8') as f: | |
| data = json.load(f) | |
| # check if entries is corrupted (object instead of array) | |
| if 'entries' in data and isinstance(data['entries'], dict): | |
| print(f" Fixing: {os.path.basename(filepath)}") | |
| entries_dict = data['entries'] | |
| if entries_dict: | |
| sorted_keys = sorted(entries_dict.keys(), key=lambda x: int(x)) | |
| entries_array = [entries_dict[key] for key in sorted_keys] | |
| else: | |
| entries_array = [] | |
| data['entries'] = entries_array | |
| with open(filepath, 'w', encoding='utf-8') as f: | |
| json.dump(data, f, indent=2) | |
| return True | |
| else: | |
| return False | |
| except Exception as e: | |
| print(f" Error processing {os.path.basename(filepath)}: {str(e)}") | |
| return False | |
| def process_timelines(timeline_dir, backup_dir): | |
| timeline_files = [f for f in os.listdir(timeline_dir) | |
| if f.startswith('timeline_') and f.endswith('.json')] | |
| if not timeline_files: | |
| return 0, 0 | |
| os.makedirs(backup_dir, exist_ok=True) | |
| fixed_count = 0 | |
| for filename in timeline_files: | |
| filepath = os.path.join(timeline_dir, filename) | |
| backup_path = os.path.join(backup_dir, filename) | |
| shutil.copy2(filepath, backup_path) | |
| if fix_timeline_file(filepath): | |
| fixed_count += 1 | |
| return len(timeline_files), fixed_count | |
| def find_timeline_dirs(steam_base): | |
| timeline_dirs = [] | |
| for user_dir in os.listdir(steam_base): | |
| user_path = os.path.join(steam_base, user_dir) | |
| if not os.path.isdir(user_path) or not user_dir.isdigit(): | |
| continue | |
| gamerecordings_path = os.path.join(user_path, "gamerecordings") | |
| if not os.path.exists(gamerecordings_path): | |
| continue | |
| # find all timelines directories recursively | |
| for root, dirs, files in os.walk(gamerecordings_path): | |
| if 'timelines' in dirs and 'timelines_backup' not in root: | |
| timeline_path = os.path.join(root, 'timelines') | |
| if 'timelines_backup' not in timeline_path: | |
| timeline_dirs.append(timeline_path) | |
| return timeline_dirs | |
| def main(): | |
| steam_base = r"C:\Program Files (x86)\Steam\userdata" | |
| if not os.path.exists(steam_base): | |
| print(f"Steam userdata directory not found: {steam_base}") | |
| return | |
| timeline_dirs = find_timeline_dirs(steam_base) | |
| if not timeline_dirs: | |
| print("No timeline directories found") | |
| return | |
| print(f"Found {len(timeline_dirs)} timeline directories\n") | |
| total_files = 0 | |
| total_fixed = 0 | |
| processed_dirs = {} | |
| for timeline_dir in timeline_dirs: | |
| parts = timeline_dir.split(os.sep) | |
| user_id_index = parts.index('userdata') + 1 | |
| user_id = parts[user_id_index] | |
| gamerecordings_index = parts.index('gamerecordings') | |
| relative_path = os.sep.join(parts[gamerecordings_index:]) | |
| parent_dir = os.path.dirname(timeline_dir) | |
| backup_dir = os.path.join(parent_dir, "timelines_backup") | |
| if user_id not in processed_dirs: | |
| processed_dirs[user_id] = 0 | |
| processed_dirs[user_id] += 1 | |
| print(f"User {user_id} - {relative_path}") | |
| file_count, fixed_count = process_timelines(timeline_dir, backup_dir) | |
| if file_count > 0: | |
| print(f" Found {file_count} files, fixed {fixed_count}\n") | |
| else: | |
| print(f" No timeline files found\n") | |
| total_files += file_count | |
| total_fixed += fixed_count | |
| print(f"\nSummary:") | |
| for user_id, count in processed_dirs.items(): | |
| print(f" User {user_id}: {count} timeline directories processed") | |
| print(f"\nTotal: Fixed {total_fixed} out of {total_files} files") | |
| if __name__ == "__main__": | |
| main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment