-
Notifications
You must be signed in to change notification settings - Fork 0
GoG : Installing games
The Galaxy Client supports different methods to download and install games depending on the target platform of the game
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
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.
-
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
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
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
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
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
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.
Just append a GALAXY_PATH to endpoint path to download the file. (Depot Informations)
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
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
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
}
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)
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.