outseeker Posted September 19, 2025 Share Posted September 19, 2025 Those who run an operating system unsupported by Steam, who would just like to play the games they bought that were designed to run on their systems find themselves in a bit of a bind once a new game update is due: updates won't install and are considered "corrupted" by Steam. This is apparently because Steam introduced ZSTD compression into the client and ofc unsupported versions don't get that update, so we can't install newly published game updates via Steam, but there is a quite convenient solution available. A tool called Depot Downloader can download and perform the game updates for us, however there are a few hurdles involved usually. It's a command line thing, so it's not super user friendly, and there's a Steam acf file that needs updating to indicate to Steam that it doesn't have to keep trying and failing to download and install the update for the game in question, that you would normally have to manually edit in a text editor. You'd also need to find the depot numbers to feed to the command line, so DD knows what exactly to download for you, however I found a Python script some legend had written to read an acf file, call DepotDownloader to update that single game, then update its acf file to let Steam know it's updated, so you can play it again. I've just searched my bookmarks and actually totally lost the (I believe Github) page where he'd just left the code in a discussion/comment if I remember right (sorry dude, I definitely wanted to credit your work I built on!), but I had grabbed his code previously, and I've expanded it to update any game that needs it, fully automatically aside from the prompt letting you know the state of any particular game it finds, asking if you wanna update it. I gave it a lil configuration area and some other lil prompts/logic to suit our purposes too :> On Win7, I have Python 3.6.2 Installed to run this script, for reference. Here's the full how to install/use process if you'd like it: 1. Grab and install a version of Python compatible with your system (3.8 is apparently newest Win7 has available Google reckons) 2. Grab DepotDownloader-Framework from its Github page ("Download a binary from the releases page" if you're on the main page) 3. Extract the full contents of the DepotDownloader archive to Steam\SteamApps\depots (that's a new folder for it called depots) 4. In the new depots folder, double click DepotDownloader.exe to run it once, just to make sure it runs. It should popup to let u know that's not how u use it. If that doesn't happen, hopefully it will tell u why not- I don't think I had a problem there. 5. Highlight and copy pasta the sauce code at the bottom of this post into your preferred text editor (apols in advance if it's ugly, I don't know this language specifically lol first time basically but don't mess with the indentation is all I can tell u for sure) 6. Edit the Configuration portion of the sauce to your tastes. Specifically, set your steamappsfolder and steamusername, and set rememberpassy = False the first time you run it so it can prompt you. If you leave it as True on first run, it will just fail bc no password I think. 7. Save that file as Steam_Update.py in your SteamApps folder. It should be chilling in there with some .acf files. Make sure it's not actually called Steam_Update.py.txt or something dumb like Notepad will do if u leave it as .txt in the selection box while saving. 8. In SteamApps where you just saved the .py script, right click Steam_Update.py and click Create Shortcut This shortcut will allow you to customise what little interface you do see, like you can right click and click Properties on it to see lots of nice tabs. It also makes sure we start the script in the correct folder context, so it should actually work. Once created u can put it wherever u like. 9. CLOSE STEAM. I have not had it happy with me logging into steam twice simultaneously tho it allegedly isn't supposed to be a problem. 10. In SteamApps, double click the Shortcut to the py script you made, and observe the nice explanation of the process as things are checked. If a game is found to have an update pending, and is in a relevant state such as Steam considering it Corrupted, you are prompted to update it. Watch the update happening for any obvious errors, and if it all looks good you can confirm you want to update the Steam acf file. If something didn't work right during the update process for any reason, you can hit N at this point to not update the acf file, so you can try it again. 11. Extra step: once you've successfully updated the game(s), Steam still has its leftover "corrupted" files it downloaded, in the SteamApps\Downloading folder. It will probably clean them up next time an update is due per-game, but you can delete that whole Downloading folder manually, or do it via Steam's Settings > Downloads > "Clear Cache" button instead. Could do it at step 9 really before closing Steam, for maximum efficiency. That's it! At this point if any game fails to update in future, you can close steam, open up SteamApps and/or hit the py script shortcut, and DepotDownloader will prompt you for passy, 2FA if relevant, and confirm any game update it finds to be pending/borked. You can set rememberpassy = True again in the config area of the python script and it's supposed to remember it, but idk if it's time limited or what still. *Please note that none of this allows any nefarious leeching from Steam, or any access to anything you don't have on your Steam account. The script is some regex stuff to parse the acf files I pinched from our helpful friend, that I don't know how to do myself, wrapped in a basic process to check and update any games that are not in a happy and installed state, which I made as a novice. It's plainly readable in text form, and squeaky clean to the best of my knowledge. It's just something I made for me, but sharing is caring, and I asked Klei for some kind of solution, so it pleases me to be able to provide it myself for everyone instead <3 from collections import OrderedDict import re import json import sys import os from os import listdir from os.path import isfile, join # ------------------ [ Configuration! ] --------------------------- steamappsfolder = r"C:\Program Files (x86)\Steam\steamapps" # Path to your SteamApps folder (leave the r alone) steamusername = "yournamegoeshere" # Steam Login to use for the downloads steampassy = "" # Steam Passy! :O warning, not an excellent idea to keep # note: run this one time with rememberpassy = False, so you can enter your passy and I think it will be cached by downloader at least in theory.. verbosemode = False # Print off each line of the .acf as things are being read rememberpassy = True # Tell Depot to remember your steampassy, else prompt each time # don't use rememberpassy on the first run, as it doesn't seem to prompt you for a password and just fails lol promptuser = True # Prompt "Update? Y/N", else just always try to update # ------------------ [ /Configuration ] --------------------------- doingupdates = False def get_yes_no_input(prompt_message): while True: user_input = input(f"{prompt_message} (yes/no): ").lower().strip() if user_input in ['yes', 'y']: return True elif user_input in ['no', 'n']: return False else: print("Invalid input. Please enter 'yes' or 'no'.") def parseobj(tokens): global doingupdates if type(tokens) == str: tokens = re.split(r'[\t\r\n]+', tokens) tokens.reverse() obj = OrderedDict() while len(tokens): nextvalisstateflags = False nt = tokens.pop() if nt in ["}", ""]: return obj elif nt.startswith('"'): # we have a key name (nt) nt = json.loads(nt) val = tokens.pop() if verbosemode is True: if nt == "manifest": print("\nReading Line: " + nt, end="") else: print("Reading Line: " + nt, end="") if nt == "name": # Print the name for non-debug mode's benefit if verbosemode == False: print(json.loads(val)) if nt == "StateFlags": nextvalisstateflags = True if val.startswith('"'): # we have a value (val) obj[nt] = json.loads(val) if verbosemode is True: print(" (" + val + ")") if nextvalisstateflags == True: if obj[nt] == "4": print("Game has no pending updates marked") elif obj[nt] == "1538": print("Game is marked as Download Content Unavailable (StateFlags 1538)") if promptuser: dotheupdate = get_yes_no_input("Attempt to update it?") if not dotheupdate: doingupdates = False elif dotheupdate: doingupdates = True else: doingupdates = True elif obj[nt] == "1542": print("Game is marked as Corrupted Download (StateFlags 1542)") if promptuser: dotheupdate = get_yes_no_input("Attempt to update it?") if not dotheupdate: doingupdates = False elif dotheupdate: doingupdates = True else: doingupdates = True else: print("Game has unknown StateFlags (" + obj[nt] + ")") if promptuser: dotheupdate = get_yes_no_input("Attempt to update it anyway?") if not dotheupdate: doingupdates = False elif dotheupdate: doingupdates = True else: doingupdates = True nextvalisstateflags = False elif val == "{": # print("\n\t", end="") obj[nt] = parseobj(tokens) else: raise Exception("nt = %r" % nt) def dumpobj(obj, indent=0): s = "" for key in obj: s += "\t" * indent + json.dumps(key) if type(obj[key]) == OrderedDict: s += "\n" + "\t" * indent + "{\n" + dumpobj(obj[key], indent + 1) + "\t" * indent + "}\n" else: s += "\t\t%s\n" % json.dumps(obj[key]) return s # Grab an array of the .acf files in the steamapps folder steamappsfiles = [f for f in listdir(steamappsfolder) if ".acf" in join(steamappsfolder, f) and "appmanifest_" in join(steamappsfolder, f) and isfile(join(steamappsfolder, f))] print(str(len(steamappsfiles)) + " Games Found To Check") for gameacf in steamappsfiles: with open(steamappsfolder + "\\" + gameacf, "r") as filetoread: print("\nParsing " + steamappsfolder + "\\" + gameacf + "...") # steamappsfolder = os.path.dirname(f.name) # Moved to Config data = filetoread.read() manifest = parseobj(data) # print(dumpobj(manifest)) print("File Read Complete. Updating: " + str(doingupdates)) if doingupdates: doingupdates = False if 'AppState' in manifest: appstate = manifest['AppState'] if 'StagedDepots' not in appstate: print("Nothing is Staged to be downloaded by Steam! You need to have Steam try to update the game first") continue print("\nStarting Update!") # username = sys.argv[sys.argv.index("-username") + 1] appstate = manifest['AppState'] weredonehere = False if rememberpassy: rememberpassword = " -remember-password " + steampassy # it makes us provide the password (at least once?) if we use this, but it doesn't prompt for a password >.< else: # rememberpassword = " -password" rememberpassword = "" # has to be blank else it doesn't prompt for passy for some reason for depotkey in appstate['StagedDepots']: cmd = \ "depots\\DepotDownloader.exe -app " + appstate['appid'] + \ " -depot " + depotkey + " -manifest " + appstate['StagedDepots'][depotkey]['manifest'] + \ " -username " + steamusername + rememberpassword + " -dir \"" + \ steamappsfolder + "\\common\\" + appstate['installdir'] + "\" -validate" print("Trying to run (from current directory " + os.getcwd() + "): " + cmd) #os.system(cmd) #print("Assuming the above succeeded - Removing Update Required status from the .acf file...") thereturncode = os.system(cmd) if thereturncode == 0: print("Success! Removing \"Update Required\" status from the .acf file...", flush=True) else: print("No bueno it seems. Cancelling any edits to the .acf file so you can find the problem and retry.", flush=True) print("I suggest putting this .py script in steamapps, and the depot downloader in steamapps\\depots ", flush=True) # need to handle this and skip further changes/code below weredonehere = True continue installed_depot = appstate['StagedDepots'][depotkey] print("Removing dlcappid") del installed_depot['dlcappid'] appstate['InstalledDepots'][depotkey] = installed_depot print("Removing " + str(depotkey) + " from StagedDepots") del appstate['StagedDepots'][depotkey] if not weredonehere: print("Setting StateFlags to 4 - Installed") appstate['StateFlags'] = "4" print("Setting UpdateResult to 0") appstate['UpdateResult'] = "0" print("Setting StagingSize to 0") appstate['StagingSize'] = "0" print("Setting buildid to current (" + appstate['TargetBuildID'] + ")") appstate['buildid'] = appstate['TargetBuildID'] print("Setting BytesStaged") appstate['BytesStaged'] = appstate['BytesToStage'] print("Setting BytesDownloaded") appstate['BytesDownloaded'] = appstate['BytesToDownload'] # print(dumpobj(manifest)) savechoice = get_yes_no_input("Do you want to save changes made to the .acf file?") if savechoice: with open(steamappsfolder + "\\" + gameacf, "w") as filetowrite: filetowrite.write(dumpobj(manifest)) else: weredonehere = False Link to comment https://forums.kleientertainment.com/forums/topic/168070-windows-7-compatibility-of-game-update-system-depot-downloader-workaround-for-steam-users/ Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now