require("dotenv").config() const express = require("express") const app = express() const port = process.env.SERVER_PORT || 3000; app.use(express.json()); app.get("/", (req, res) => { // load index res.sendFile(__dirname + "/static/index.html") }); app.post("/", async (req, res) => { // Validate request body if (!req.body.type || req.body.type !== "batching") { return res.status(400).json({ error: "Invalid request type", status: "error" }); } if (!req.body.data || !Array.isArray(req.body.data)) { return res.status(400).json({ error: "Invalid data format", status: "error" }); } // Build the batch request body const batchRequests = req.body.data.map(item => { console.log(item) const assetId = item; if (!assetId) { return { assetId, requestId: assetId, status: "failure", url: "", additional: "Missing assetId." }; } return { assetId, requestId: assetId }; }); // If body.cookie is provided, use it, else use process.env.COOKIE const cookie = req.body.cookie || process.env.COOKIE; console.log(cookie) const options = { method: 'POST', headers: { authority: 'assetdelivery.roblox.com', accept: '', 'accept-language': 'en-US,en;q=0.9', 'cache-control': 'no-cache', 'content-type': 'application/json', origin: 'https://create.roblox.com', pragma: 'no-cache', referer: 'https://create.roblox.com/', 'roblox-browser-asset-request': 'true', 'roblox-place-id': '0', // Use a default or placeholder value if needed 'sec-ch-ua': '"Opera GX";v="105", "Chromium";v="119", "Not?A_Brand";v="24"', 'sec-ch-ua-mobile': '?0', 'sec-ch-ua-platform': '"Windows"', 'sec-fetch-dest': 'empty', 'sec-fetch-mode': 'cors', 'sec-fetch-site': 'same-site', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:130.0) Gecko/20100101 Firefox/130.0', Cookie: `.ROBLOSECURITY=${cookie};` }, body: JSON.stringify(batchRequests) }; try { let response = await fetch("https://assetdelivery.roblox.com/v1/assets/batch", options); let json = await response.json(); console.log(JSON.stringify(json, null, 2)) // Build the response object const responses = req.body.data.reduce((acc, item, index) => { const assetId = item; if (json[index].errors) { const errorCode = json[index].errors[0].code; acc[assetId] = { status: "failure", url: "", additional: errorCode === 403 ? "Audio is private, please use protected mode" : "Internal server error" }; } else { acc[assetId] = { status: "success", url: json[index].location }; } return acc; }, {}); res.json({ type: "batching-response", data: responses }); } catch (error) { res.status(500).json({ type: "batching-response", data: req.body.data.reduce((acc, item) => { acc[item] = { status: "failure", url: "", additional: "Request failed" }; return acc; }, {}) }); } }); app.listen(port, () => { console.log(`Listening on ${port}`); });