Skip to content

Instantly share code, notes, and snippets.

@plyrthn
Last active October 20, 2025 19:16
Show Gist options
  • Select an option

  • Save plyrthn/6f4893040e023d6f1e67efd4663a0582 to your computer and use it in GitHub Desktop.

Select an option

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.
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