Skip to content

GoG : Installing games

Paweł Lidwin edited this page Apr 3, 2024 · 10 revisions

The Galaxy Client supports different methods to download and install games depending on the target platform of the game

Linux

Self-Extracing .sh Scripts that extract an included archive. It is using a customized version of https://makeself.io/ These can easily be unpacked with unzip.

For Heroic Games Launcher purposes there is a demo tool developed for selectively downloading files directly from CDN, without downloading full installer.
Using Range headers script parses ZIP file embedded in the installer, being able to create manifests and verifying downloaded files. GitHub gist with mentioned script: https://gist.github.com/imLinguin/603c2d879c3db29eb8fff604216adfc4

This solution creates content-system like ability to download only needed files, also speeding up updating

Mac

Supports installers

  • Offline Installers

  • Online Download of files via GoGs Depot System GoG uses osx as platform name. See Windows, since steps are the same.

Windows

  • Offline Installers For every DLC and the game there is a Binary that you can run. These are mostly made with Innosetup and can be extracted with https://constexpr.org/innoextract/

  • Online Download of files via GoGs Depot system

These come in two versions

V2

This newer version allows downloading game files that are compressed using zlib with window size of 15.

I've made some of the responses shorter, for the wiki page to not get too long.

Here I'll use Stellaris in my examples. Where GAME_ID is 1508702879

PLATFORM for now can be windows and osx

Getting Builds data

GET https://content-system.gog.com/products/GAME_ID/os/PLATFORM/builds?generation=2
{
	"total_count": 197,
	"count": 5,
	"items": [
		{
			"build_id": "54948979932173870",
			"product_id": "1508702879",
			"os": "windows",
			"branch": null,
			"version_name": "3.2.2",
			"tags": [
				"csb_10_6_1_l_147"
			],
			"public": true,
			"date_published": "2021-11-22T21:59:42+0000",
			"generation": 2,
			"link": "https:\/\/cdn.gog.com\/content-system\/v2\/meta\/46\/97\/46971c97767be43494aaf31a335fe86d"
		},
	],
	"has_private_branches": true
}
  • build_id is a unique identifier of the build, allows us to check if there is an update
  • version_name is version number that can be displayed to a user
  • generation provides us with information which Depot version that build uses
  • link

Getting Meta data

This endpoint returns compressed JSON data see Decompressing Example

GET https://cdn.gog.com/content-system/v2/meta/46/97/46971c97767be43494aaf31a335fe86d
{
    "version": 2,
    "baseProductId": "1508702879",
    "platform": "windows",
    "offlineDepot": {
        "manifest": "d6e62db8b74abcffd16b624748219195",
        "size": 9605,
        "compressedSize": 1190,
        "productId": "1508702879",
        "languages": [
            "*"
        ]
    },
    "depots": [
        {
            "manifest": "9fecd730b966b6bb89048c407ca5a691",
            "size": 13988149589,
            "compressedSize": 8197754618,
            "productId": "1508702879",
            "languages": [
                "*"
            ]
        },
        {
            "manifest": "e4c7dfda9c6073b0ebe669b855dda95a",
            "size": 726642030,
            "compressedSize": 363376163,
            "productId": "1508702879",
            "languages": [
                "*"
            ]
        },
        {
            "manifest": "ee50209286b7b91c631dcd9f0bcee081",
            "size": 717211,
            "compressedSize": 709010,
            "productId": "1508702879",
            "languages": [
                "*"
            ],
            "isGogDepot": true
        },
        {
            "manifest": "8bd821e4c42eea7600b4890cf4f73efe",
            "size": 911,
            "compressedSize": 376,
            "productId": "1508702879",
            "languages": [
                "*"
            ],
            "isGogDepot": true
        }
    ],
    "products": [
        {
            "name": "Stellaris",
            "productId": "1508702879",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Anniversary Portraits",
            "productId": "1619776270",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Arachnoid Portrait Pack",
            "productId": "1897107160",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Plantoids Species Pack",
            "productId": "1999794856",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Leviathans Story Pack",
            "productId": "1122806862",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Utopia",
            "productId": "1978231244",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Synthetic Dawn Story Pack",
            "productId": "1292954230",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Apocalypse",
            "productId": "1988097366",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Humanoids Species Pack",
            "productId": "2062279897",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Distant Stars Story Pack",
            "productId": "1209094315",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Complete Soundtrack",
            "productId": "1892453534",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Infinite Frontiers eBook",
            "productId": "1439311238",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Horizon Signal",
            "productId": "1490429179",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Megacorp",
            "productId": "1316465607",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Ancient Relics",
            "productId": "2106739867",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Lithoids Species Pack",
            "productId": "1420212493",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Federations",
            "productId": "1790030450",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Necroids Species Pack",
            "productId": "2112845659",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Nemesis",
            "productId": "1488827509",
            "temp_executable": "",
            "temp_arguments": ""
        },
        {
            "name": "Stellaris: Aquatics Species Pack",
            "productId": "1253915653",
            "temp_executable": "",
            "temp_arguments": ""
        }
    ],
    "dependencies": [
        "DirectX",
        "MSVC2010",
        "MSVC2013",
        "MSVC2015"
    ],
    "tags": [
        "csb_10_6_1_l_147"
    ],
    "buildId": "54948979932173870",
    "installDirectory": "Stellaris",
    "scriptInterpreter": true
}
  • baseProductId is id of game we just got info for
  • dependencies array contains IDs of the redistributables which we will cover later
  • products array contain names and IDs of possible DLCs (corresponding files can be gathered from depot with same productId)
  • depots the most interesting part since this array contains manifest, languages supported by this depot and size information

Depot informations

This is a manifest we got from first element of depots array - 9fecd730b966b6bb89048c407ca5a691 Based on that we can provide ourselves with exact URL to the resource. Of course you want to loop through every depot you want to download.

GALAXY_PATH based on manifest we have will look like this 9f/ec/9fecd730b966b6bb89048c407ca5a691 Do you see a patetrn here? 😄

GET https://cdn.gog.com/content-system/v2/meta/GALAXY_PATH
{
    "depot": {
        "items": [
            {
                "path": "checksum_manifest.txt",
                "chunks": [
                    {
                        "md5": "e5a2b56f4c9af322712454142f892a22",
                        "size": 525,
                        "compressedMd5": "667156d827dd796348128bdcce855942",
                        "compressedSize": 130
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": "ChangeLog.txt",
                "chunks": [
                    {
                        "md5": "6703c3386a5cfa8b4fcb06f3dfe5b48a",
                        "size": 8124,
                        "compressedMd5": "c85ce70bb62b05c9da33ab6cb76fb708",
                        "compressedSize": 3425
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": "compile_newly_generated_orbis_shaders.bat",
                "flags": [
                    "executable"
                ],
                "sha256": "f50a69dd4188ce348c7451b457939dec8d6ba043f5ccfc29a79eb2bca3838203",
                "chunks": [
                    {
                        "md5": "0fe6a234f8196caffbf5002d1e0f8b34",
                        "size": 719,
                        "compressedMd5": "9906e663fbf280b6adf3979a4811f03f",
                        "compressedSize": 262
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": "AutoClientScript.py",
                "chunks": [
                    {
                        "md5": "1a626fff1b5337f93ca9028df36310d5",
                        "size": 7351,
                        "compressedMd5": "af3b97dd9fe5ebd63d5868163f8beeb3",
                        "compressedSize": 2346
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": "AutoClientScriptOvernight.py",
                "chunks": [
                    {
                        "md5": "c1241430051f4e4688cfdfa35ee97be0",
                        "size": 5269,
                        "compressedMd5": "bac05c07120c5e456f8c9b5122bb300f",
                        "compressedSize": 1849
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": ".gitignore",
                "chunks": [
                    {
                        "md5": "802d091cfc70f7c699213e739e8a5f76",
                        "size": 37,
                        "compressedMd5": "bceb622a9929fa9279c05174f1904c94",
                        "compressedSize": 45
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": "common/graphical_culture/00_graphical_culture.txt",
                "chunks": [
                    {
                        "md5": "ada9e0d31cfe7f7c419bd8e51f7a7e2c",
                        "size": 20514,
                        "compressedMd5": "6f4791391d7c9cb053c139248cf2c21d",
                        "compressedSize": 1280
                    }
                ],
                "type": "DepotFile"
            },
            {
                "path": "common/graphical_culture/01_graphical_culture_megacorp.txt",
                "chunks": [
                    {
                        "md5": "4203ca4c2d8169fa6823331b32558da0",
                        "size": 843,
                        "compressedMd5": "b40ded420d30bb833445096a38e709e5",
                        "compressedSize": 381
                    }
                ],
                "type": "DepotFile"
            }
        ]
    },
    "version": 2
}

Depot objects breakdown:

  • path - Path to target file
  • chunks - for bigger files, this can have thousands of chunks
  • type - DepotFile or DepotDirectory, DepotDirectory object contains only path for the directory to be created
  • sha256 - sum for uncompressed file, this is present only when there are more than one chunks
  • md5 - sum for uncompressed file, this is present only when there are more than one chunks

If file contains one chunk sha256 and md5 are available in that one chunk object. Note: sometimes sha256 isn't present, same happens with md5. Always one of them is available

Obtaining secure link

This endpoint requires Authentication This provides us a CDN's list with priority, parameters and how to fill url_format with them.

GET https://content-system.gog.com/products/<GAME_ID>/secure_link?generation=2&_version=2&path=/
{
	"product_id": 1207658924,
	"type": "depot",
	"urls": [
		{
			"endpoint_name": "lumen",
			"url_format": "{base_url}\/token=nva={expires_at}~dirs={dirs}~token={token}{path}",
			"parameters": {
				"base_url": "https:\/\/gog-cdn-lumen.secure2.footprint.net",
				"path": "\/content-system\/v2\/store\/1207658924",
				"token": "0652897d4916f2dc89dfd",
				"expires_at": 1644571499,
				"dirs": 4
			},
			"priority": 97,
			"max_fails": 100,
			"supports_generation": [
				2
			]
		},
		{
			"endpoint_name": "akamai_edgecast_proxy",
			"url_format": "{base_url}\/{path}?__token__={token}",
			"parameters": {
				"base_url": "https:\/\/cdn-akamai-ec.gog-services.com",
				"path": "content-system\/v2\/store\/1207658924",
				"token": "exp=1644656999~acl=\/content-system\/v2\/store\/1207658924\/*~hmac=a3c112659cfb398a1c860ca010028e5ccfda9176836d93e67dcca4f58d322cab"
			},
			"priority": 1,
			"max_fails": 100,
			"supports_generation": [
				2
			]
		},
		{
			"endpoint_name": "edgecast",
			"url_format": "{base_url}\/{path}?{token}",
			"parameters": {
				"base_url": "https:\/\/cdn.gog.com",
				"path": "content-system\/v2\/store\/1207658924",
				"token": "<Token will be here>"
			},
			"priority": 1,
			"max_fails": 100,
			"supports_generation": [
				1,
				2
			]
		},
		{
			"endpoint_name": "high_winds",
			"url_format": "{base_url}\/{path}?ttl={ttl}&hw_l={l}&hw_token={token}&_token={gog_token}&source={source}",
			"parameters": {
				"base_url": "https:\/\/cdn-hw.gog.com",
				"path": "content-system\/v2\/store\/1207658924",
				"ttl": 1644656999,
				"l": 35,
				"token": "abaf09dab36fcfcee139292048677cba",
				"gog_token": "<Token will be here>",
				"source": "hw"
			},
			"priority": 1,
			"max_fails": 10,
			"supports_generation": [
				2
			]
		}
	]
}

IMPORTANT When selecting the CDN you should pick that with highest priority.

If some CDN doesn't work properly, you should fallback to ones with lower priority.

To not spam this endpoint for each chunk, it's advised to store the best endpoint and append GALAXY_PATH we learned how to calculate earlier, to the path parameter.

You can now obtain compressed chunk of the file with this formula. Decompressing files works the same way as decompressing the responses of meta endpoints. zlib encoded with 15 window size.

File download

Just append a GALAXY_PATH to endpoint path to download the file. (Depot Informations)

V1

Steps are really similar to V2. Differences are response structure, no compression, no file chunks. In this example we will cover it based on data of Indiana Jones® and the Emperor's Tomb™ - where GAME_ID is 1425034773

Getting Builds data

GET https://content-system.gog.com/products/GAME_ID/os/PLATFORM/builds?generation=1

Note you can select generation you support. However you probably should get it with generation=2 parameter and then detect depot version used in preferred build.

{
	"total_count": 2,
	"count": 2,
	"items": [
		{
			"build_id": "48953126409549870",
			"product_id": "1425034773",
			"os": "windows",
			"branch": null,
			"version_name": "25032016",
			"tags": [],
			"public": true,
			"date_published": "2016-03-25T14:40:55+0000",
			"generation": 1,
			"link": "https://gog-cdn-lumen.secure2.footprint.net/content-system/v1/manifests/1425034773/windows/60437948/repository.json",
			"legacy_build_id": 60437948
		},
		{
			"build_id": "15741",
			"product_id": "1425034773",
			"os": "windows",
			"branch": null,
			"version_name": "",
			"tags": [],
			"public": true,
			"date_published": "2015-05-29T14:39:40+0000",
			"generation": 1,
			"link": "https://gog-cdn-lumen.secure2.footprint.net/content-system/v1/manifests/1425034773/windows/39281980/repository.json",
			"legacy_build_id": 39281980
		}
	],
	"has_private_branches": false
}
  • link - url to manifest (meta)
  • generation - version of the depot

Getting Meta data

GET https://gog-cdn-lumen.secure2.footprint.net/content-system/v1/manifests/1425034773/windows/60437948/repository.json

If you wonder where we got that url from, see Getting Builds Data

{
    "product" : {
        "rootGameID" : "1425034773",
        "timestamp"  : 60437948,
        "gameIDs"    : [
            {
                "standalone" : true,
                "name"       : {
                    "en" : "Indiana Jones\u00AE and the Emperor's Tomb\u2122"
                },
                "gameID"     : "1425034773",
                "dependencies" : [
                ]
            }
        ],
        "support_commands" : [
            {
                "languages" : [
                    "Neutral"
                ],
                "argument"  : "",
                "gameID"    : "1425034773",
                "systems"   : [
                    "Windows"
                ],
                "executable" : "/galaxy_indiana_jones_and_the_emperors_tomb_2.0.0.7.exe"
            }
        ],
        "depots"           : [
            {
                "languages" : [
                    "Neutral"
                ],
                "manifest"  : "34a5fd5a-b54d-4d15-ae99-ae02d8f0a6d2.json",
                "gameIDs"   : [
                    "1425034773"
                ],
                "size"      : "1296880",
                "systems"   : [
                    "Windows"
                ]
            },
            {
                "languages" : [
                    "English"
                ],
                "manifest"  : "5a71e7ac-4725-41c9-84aa-ee6f3c633fab.json",
                "gameIDs"   : [
                    "1425034773"
                ],
                "size"      : "1347732297",
                "systems"   : [
                    "Windows"
                ]
            },
            {
                "languages" : [
                    "German"
                ],
                "manifest"  : "5c41eff9-faee-4c67-bb12-c62ae45144ef.json",
                "gameIDs"   : [
                    "1425034773"
                ],
                "size"      : "1363469294",
                "systems"   : [
                    "Windows"
                ]
            },
            {
                "languages" : [
                    "French"
                ],
                "manifest"  : "82187f21-e245-439b-879d-926c3e96fee1.json",
                "gameIDs"   : [
                    "1425034773"
                ],
                "size"      : "1370017724",
                "systems"   : [
                    "Windows"
                ]
            },
            {
                "languages" : [
                    "Italian"
                ],
                "manifest"  : "22e20430-b65e-4ed6-ba75-33c6cd11d475.json",
                "gameIDs"   : [
                    "1425034773"
                ],
                "size"      : "1352800619",
                "systems"   : [
                    "Windows"
                ]
            },
            {
                "redist" : "DirectX",
                "executable" : "__redist/DirectX/DXSETUP.exe",
                "argument"   : "/silent"
            }
        ],
        "installDirectory" : "Indiana Jones and the Emperor's Tomb",
        "projectName"      : "Indiana Jones\u00AE and the Emperor's Tomb\u2122"
    },
    "version" : 1
}

Depot informations

URL is basically a repository.json url from previous step, instead of repository.json we replace it with manifest of the depot we want to get more info about.

GET https://gog-cdn-lumen.secure2.footprint.net/content-system/v1/manifests/1425034773/windows/60437948/5a71e7ac-4725-41c9-84aa-ee6f3c633fab.json
{
	"version": 1,
	"depot": {
		"name": "Indiana Jones® and the Emperor's Tomb™",
		"files": [
			{
				"path": "/GameData/indy/meshes/Props/Mission07/dragonorb.gin",
				"size": 0
			},
			{
				"path": "/EmperorsTomb.exe",
				"size": 0
			},
			{
				"offset": 1318453206,
				"hash": "e879f39f83301a8ad8ed3747e1acf614",
				"url": "1425034773/main.bin",
				"path": "/GameData/indy/meshes/Chars/Common/r_indy.csv",
				"size": 8
			},
			{
				"offset": 1185917263,
				"hash": "99c06ff9132cb23b4b1d490c42ed7447",
				"url": "1425034773/main.bin",
				"path": "/GameData/indy/interfc/Update.bat",
				"size": 19
			},
			{
				"offset": 1185917282,
				"hash": "ee524ccf5ccdccae545f52a533b73e8a",
				"url": "1425034773/main.bin",
				"path": "/GameData/indy/interfc/Fonts/convert.bat",
				"size": 25
			},
			{
				"offset": 1206430843,
				"hash": "0f3fd377d5c091316b14bdff5572247e",
				"url": "1425034773/main.bin",
				"path": "/GameData/indy/meshes/Props/Mission07/incense.mtx",
				"size": 36
			},
			{
				"offset": 1206430843,
				"hash": "0f3fd377d5c091316b14bdff5572247e",
				"url": "1425034773/main.bin",
				"path": "/GameData/indy/meshes/Props/Weapons/throwing.mtx",
				"size": 36
			},
			{
				"offset": 1206430843,
				"hash": "0f3fd377d5c091316b14bdff5572247e",
				"url": "1425034773/main.bin",
				"path": "/GameData/indy/meshes/Props/Arch/Lights/spotlight.mtx",
				"size": 36
			}
                        THERE IS MORE BUT I SHORTENED A RESPONSE FOR DOCS PURPOSES
                ]
       }
}
  • hash - md5 checksum for verifying the file
  • url path to the resource
  • path - path where file should be located
  • offset - useful for Range header later
  • size - size of the file, will be useful for Range header too

As you can see all of them are linking to the same file. Here comes a Range header you should send with a download request. (more info later)

Generating a secure link

This endpoint requires Authentication This provides us a CDN's list with priority, parameters and how to fill url_format with them. (just like V2)

Since in one manifest there are also depots for DLCs you need to generate secure link for each one - PRODUCT_ID

It may be possible to ommit PRODUCT_ID and get secure link for BUILD_ID directly (not tested)

GET https://content-system.gog.com/products/<GAME_ID>/secure_link?_version=2&type=depot&path=/PLATFORM/BUILD_ID/PRODUCT_ID

####​ File downloading

In each secure link, you can access a /main.bin. This is a blob of all files related to that product in the build.
For each file you need to create an appropriate Range header based on the file offset and size.