Last active
November 13, 2025 09:25
-
-
Save redzumi/ef7bda29bcd39977a32c6e0858aa7880 to your computer and use it in GitHub Desktop.
Minecraft Modrinth Mods Downloader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import axios from "axios"; | |
| import fs from "fs"; | |
| import path from "path"; | |
| /** links.txt | |
| https://modrinth.com/datapack/dungeons-and-taverns/versions?g=1.21.4&l=fabric | |
| https://modrinth.com/datapack/dungeons+/versions?g=1.21.4&l=fabric | |
| https://modrinth.com/datapack/explorify/versions?g=1.21.4&l=fabric | |
| https://modrinth.com/datapack/hybrid-beta | |
| */ | |
| const links = fs.readFileSync( | |
| path.join(import.meta.dirname, "links.txt"), | |
| "utf8" | |
| ); | |
| const projectIds = links | |
| .split("\n") | |
| .filter((link) => link.includes("modrinth.com")) | |
| .map((link) => link.split("?")[0].replace("/versions", "").split("/").pop()); | |
| const targetGameVersion = "1.21.4"; | |
| const targetLoader = "fabric"; | |
| const getDownloadInfo = async (projectId) => { | |
| const { versions, project } = await getProjectInfo(projectId); | |
| const filteredVersions = versions.filter( | |
| (version) => | |
| version.game_versions.includes(targetGameVersion) && | |
| version.loaders.includes(targetLoader) | |
| ); | |
| const sortedVersions = filteredVersions.sort( | |
| (a, b) => new Date(b.date_published) - new Date(a.date_published) | |
| ); | |
| if (sortedVersions.length === 0) { | |
| console.error( | |
| `No ${targetGameVersion} ${targetLoader} version found for ${projectId}` | |
| ); | |
| return { downloadUrl: null, downloadName: null, prefix: null }; | |
| } | |
| return { | |
| downloadUrl: sortedVersions[0].files[0].url, | |
| downloadName: sortedVersions[0].files[0].filename, | |
| prefix: getPrefix(project.client_side, project.server_side), | |
| }; | |
| }; | |
| const getVersions = async (projectId) => { | |
| const baseUrl = "https://api.modrinth.com/v2/"; | |
| const response = await axios.request({ | |
| method: "get", | |
| url: `${baseUrl}project/${projectId}/version`, | |
| headers: {}, | |
| }); | |
| return response.data; | |
| }; | |
| const getProject = async (projectId) => { | |
| const baseUrl = "https://api.modrinth.com/v2/"; | |
| const response = await axios.request({ | |
| method: "get", | |
| url: `${baseUrl}project/${projectId}`, | |
| headers: {}, | |
| }); | |
| return response.data; | |
| }; | |
| const getProjectInfo = async (projectId) => { | |
| const [versions, , project] = await Promise.all([ | |
| getVersions(projectId), | |
| sleep(1000), | |
| getProject(projectId), | |
| ]); | |
| return { versions, project }; | |
| }; | |
| /** | |
| * 'c' - is client only, should be only in 'mods' on client side | |
| * 'cs' - both sides, should be in 'mods' for server and client side | |
| */ | |
| const getPrefix = (client_side, server_side) => { | |
| if (server_side === "unsupported") { | |
| return "c"; | |
| } | |
| return "cs"; | |
| }; | |
| const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); | |
| for (const projectId of await projectIds) { | |
| const index = projectIds.indexOf(projectId); | |
| const { downloadUrl, downloadName, prefix } = await getDownloadInfo( | |
| projectId | |
| ); | |
| if (downloadUrl === null) { | |
| console.error(`No download URL found for ${projectId}`); | |
| continue; | |
| } | |
| const downloadResponse = await axios.get(downloadUrl, { | |
| responseType: "stream", | |
| }); | |
| const writer = fs.createWriteStream( | |
| path.join(import.meta.dirname, "mods", `${prefix}_${downloadName}`) | |
| ); | |
| downloadResponse.data.pipe(writer); | |
| writer.on("finish", () => { | |
| console.log(`Downloaded ${downloadName}`); | |
| }); | |
| writer.on("error", (error) => { | |
| console.error(`Error downloading ${downloadName}: ${error}`); | |
| }); | |
| await sleep(1000); | |
| console.log(`Downloaded ${projectId}`); | |
| console.log(`${index + 1} of ${projectIds.length} downloaded`); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment