Skip to content

Instantly share code, notes, and snippets.

@einstein95
Last active April 5, 2025 11:10
Show Gist options
  • Save einstein95/7e700b6242c77d3f9a01e3059d4f397b to your computer and use it in GitHub Desktop.
Save einstein95/7e700b6242c77d3f9a01e3059d4f397b to your computer and use it in GitHub Desktop.
#!/usr/bin/python3
import argparse
import re
import subprocess
from pathlib import Path
import requests
ID_RE = re.compile(r"/(\d+)(?:/|$)")
TOKEN_RE = re.compile(r"token=([^&]+)")
def fetch_json(session: requests.Session, url: str, data: str = "") -> dict:
"""Fetch JSON data from a URL with error handling."""
response = session.post(url, data=data) if data else session.get(url)
if not response.ok:
if "cf-cookie-error" in response.text:
print("Cloudflare cookie error. Please try again later.")
else:
print(f"Error fetching {url}: {response.status_code}")
exit(1)
try:
return response.json()
except requests.exceptions.JSONDecodeError:
print(f"Error decoding JSON from {url}")
exit(1)
def download_file(session: requests.Session, url: str, file_path: str):
"""Download a file using wget with session cookies."""
cookies = {
cookie.name: cookie.value
for cookie in session.cookies
if cookie.name in ("gjexpires", "gjsig")
}
cookies_str = "; ".join(
f"{name}={value}" for name, value in cookies.items() if value
)
subprocess.call(
["wget", "--header", f"Cookie: {cookies_str}", "-O", file_path, url]
)
def main():
parser = argparse.ArgumentParser(description="Download game files from GameJolt")
parser.add_argument("url", help="URL of the game on GameJolt")
args = parser.parse_args()
session = requests.Session()
session.headers.update(
{
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
}
)
match = ID_RE.search(args.url)
if not match:
print("Invalid URL. Please provide a valid GameJolt game URL.")
exit(1)
game_id = match.group(1)
overview_url = (
f"https://gamejolt.com/site-api/web/discover/games/overview/{game_id}?ignore"
)
response = fetch_json(session, overview_url)
for build in response["payload"]["builds"]:
if build["type"] == "downloadable":
continue
build_id = build["id"]
download_url_response = fetch_json(
session,
f"https://gamejolt.com/site-api/web/discover/games/builds/get-download-url/{build_id}",
data="{}",
)
token_match = TOKEN_RE.search(download_url_response["payload"]["url"])
if not token_match:
print("Token not found in URL.")
exit(1)
token = token_match.group(1)
game_server_response = fetch_json(
session, f"https://gamejolt.net/site-api/gameserver/{token}"
)
url = game_server_response["payload"]["url"].replace("https://", "http://")
path = Path("/".join(url.split("/")[2:-1]))
file_name = url.split("/")[-1]
file_path = path / file_name
path.mkdir(parents=True, exist_ok=True)
download_file(session, url, str(file_path))
if __name__ == "__main__":
main()
@einstein95
Copy link
Author

Why

Cloudflare error, fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment