Skip to content

Instantly share code, notes, and snippets.

@Lewiscowles1986
Created May 19, 2025 06:26
Show Gist options
  • Save Lewiscowles1986/d509fce754bfa154659a2b8e98aeaa94 to your computer and use it in GitHub Desktop.
Save Lewiscowles1986/d509fce754bfa154659a2b8e98aeaa94 to your computer and use it in GitHub Desktop.
Forgecraft-manifest-downloader PHP
<?php
function relativeDirectory($path) {
return __DIR__ . "/" . $path;
}
$manifestPath = relativeDirectory("manifest.json");
$downloadDir = relativeDirectory("mods");
$userAgent = "CurseForge/Downloader+1.0";
$cookieFile = relativeDirectory("cookies.txt"); // Optional. Comment this line out if not using cookies.
if (!file_exists($manifestPath)) {
die("manifest.json not found\n");
}
$manifest = json_decode(file_get_contents($manifestPath), true);
if (!is_array($manifest) || !isset($manifest['files'])) {
die("Invalid manifest.json format\n");
}
// Create downloads directory
if (!is_dir($downloadDir)) {
mkdir($downloadDir, 0777, true);
}
foreach ($manifest['files'] as $file) {
$projectID = $file['projectID'];
$fileID = $file['fileID'];
$metaUrl = "https://www.curseforge.com/api/v1/mods/$projectID/files/$fileID";
$downloadUrl = "https://www.curseforge.com/api/v1/mods/$projectID/files/$fileID/download";
echo "Fetching metadata for project $projectID, file $fileID...\n";
$meta = curlGetJson($metaUrl, $userAgent, $cookieFile);
if (!$meta || !isset($meta['data']['fileName'])) {
echo "Failed to retrieve fileName\n";
continue;
}
$fileName = $meta['data']['fileName'];
$outputPath = "$downloadDir/$fileName";
echo "Downloading $fileName...\n";
$success = curlDownload($downloadUrl, $outputPath, $userAgent, $cookieFile);
if ($success) {
echo "Downloaded to $outputPath\n";
} else {
echo "Failed to download $fileName\n";
}
}
function curlGetJson($url, $userAgent, $cookieFile = null)
{
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_USERAGENT => $userAgent,
CURLOPT_FOLLOWLOCATION => true,
]);
if ($cookieFile) {
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);
}
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
function curlDownload($url, $savePath, $userAgent, $cookieFile = null)
{
$fp = fopen($savePath, 'w');
if (!$fp) return false;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_FILE => $fp,
CURLOPT_USERAGENT => $userAgent,
CURLOPT_FOLLOWLOCATION => true,
]);
if ($cookieFile) {
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookieFile);
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookieFile);
}
$success = curl_exec($ch);
curl_close($ch);
fclose($fp);
return $success;
}
@Lewiscowles1986
Copy link
Author

relativeDirectory could change.
What Might be a better option would be to build a separate script which can do the download, and then sub-process / thread that part... IDK, I like simplicity of a <100 line file today.

@Lewiscowles1986
Copy link
Author

2025 may php 8.4.7 used to test this on the all the mods 10-2.47 modpack

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