With all of the recent controversy about games getting censored for content, not necessarily against the law, but that other private companies have decided is “questionable”, I decided it might be a good idea to backup all of my Good Old Games (GOG) titles. Especially since I now have my new 10TB drive to dump them on. Because of course, GOG sells it’s games without DRM.
I started to do this manually, but it’s incredibly tedious. Surely someone has a script, and sure enough, they have (Link). It works well enough. It’s a single file, which is nice.
It needed a few things to get going though. Firstly, a Python Library.
pip install html5lib
You then have to log in, which surprisingly, didn’t ask for any 2 factor credentials, even though normally it does. That’s a bit worrying.
python.exe .\gogrepoc.py login
The next step is to build a little local database-ish file by letting it scan your library.
python.exe .\gogrepoc.py update
Finally it’s ready to download. But here is where it gets a bit fun. I have, just under 400 games on GOG. I know it’s going to take a long time to download everything, and potentially it’s going to eat up a lot of bandwidth, which screws up my gaming, and it’s likely going to get interrupted due to a myriad of potential reasons.
You can however, download games based on IDs, individually. For example, this will download Fallout 1 Classic.
python.exe .\gogrepoc.py download -id 1
I just, randomly tried ID 1 and it worked. However, the IDs are not sequential at all, nor are they all single digits. Maybe have multiple digits. Thankfully, the database-ish thing we built earlier, gog-manifest.dat, is human readable, it’s just an XML file. Each title has a lot of data in the file, but what we want is the first line for each game, “{‘_id_mirror’: 1,”.
I took this file, threw it at Claude.ai and asked it for a script that will strip out all the IDs and put them in a simple text file list, one on each line. Which is did.
The code for that file is here:
#!/usr/bin/env python3
"""
Script to extract _id_mirror values from a JSON-style file containing GOG game data.
Usage: python extract_gog_ids.py <input_filename>
Output: Creates gog_ids.txt with one ID per line
"""
import json
import sys
import ast
def extract_gog_ids(input_filename):
"""
Extract _id_mirror values from the input file and save to gog_ids.txt
Args:
input_filename (str): Path to the input JSON-style file
"""
try:
with open(input_filename, 'r', encoding='utf-8') as file:
content = file.read().strip()
# Try to parse as JSON first
try:
data = json.loads(content)
except json.JSONDecodeError:
# If JSON parsing fails, try to evaluate as Python literal
# This handles cases where the file might be Python dict/list format
try:
data = ast.literal_eval(content)
except (ValueError, SyntaxError) as e:
print(f"Error: Could not parse the file as JSON or Python literal: {e}")
return False
# Extract _id_mirror values
id_mirrors = []
if isinstance(data, list):
# Data is a list of dictionaries
for item in data:
if isinstance(item, dict) and '_id_mirror' in item:
id_mirrors.append(str(item['_id_mirror']))
elif isinstance(data, dict) and '_id_mirror' in data:
# Data is a single dictionary
id_mirrors.append(str(data['_id_mirror']))
else:
print("Error: Input data format not recognized. Expected list of dicts or single dict with '_id_mirror' key.")
return False
# Write to output file
with open('gog_ids.txt', 'w', encoding='utf-8') as output_file:
for id_mirror in id_mirrors:
output_file.write(f"{id_mirror}\n")
print(f"Successfully extracted {len(id_mirrors)} IDs to gog_ids.txt")
return True
except FileNotFoundError:
print(f"Error: File '{input_filename}' not found.")
return False
except Exception as e:
print(f"Error processing file: {e}")
return False
def main():
"""Main function to handle command line arguments"""
if len(sys.argv) != 2:
print("Usage: python extract_gog_ids.py <input_filename>")
print("Example: python extract_gog_ids.py paste.txt")
sys.exit(1)
input_filename = sys.argv[1]
success = extract_gog_ids(input_filename)
if not success:
sys.exit(1)
if __name__ == "__main__":
main()
So what I have now is an easy to use list of IDs.
Then, in a new chat, I asked Claude.ai to modify my Powershell command to run through the list, one at a time, running the download command above. BUT I also stipulated that it let me specify how many to download, this way I can do them in blocks of however many I want. This command will download the top ten IDs.
Get-Content gog_ids.txt | Select-Object -First 10 | ForEach-Object { python.exe .\gogrepoc.py download -id $_ }
Now, I could get fancier, but this works pretty well for my needs. Once it finishes, I can just, manually edit the IDs file and chop the top then IDs off.
I also found that the bandwidth needs must not be too huge because it didn’t add any additional lag while playing games while it was running.