Grabbing audio download url with lua script

Hello! If you’re unaware, Roblox is planning to private the already existing audio(longer than 6 seconds which isn’t owned by the creator, Roblox, or a partner(such as Monstercat)). Due to this change, many developers are trying to replace their current audio ids with their own.

Why I created this post:
I have found a way to grab the actual audio URL using the Roblox search API. Although this method only works for public audio, which means it will stop working after 22 of march.

Pasting the audio URL in your browser, then pressing Ctrl+S(or right-click > Save audio as) allows you to download it

Anyways, here’s the code:

--Http requests must be enabled(run game.HttpService.HttpEnabled = true in the console) 
local HttpService = game:GetService("HttpService")

local id = 142376088

function proxy(url) 
	--change roproxy.com with your desired proxy
	return url:gsub("roblox.com", "roproxy.com") 
end

--recursive
local whitelisted_errors = {"HttpError: InvalidRedirect", "HttpError: InvalidUrl", 
	"HTTP 400 (Bad Request)", "HTTP 500(Internal Server Error)"}
function GET(url, attempts) 
	attempts = attempts or 10 --10 is max default attempts
	local success, result = pcall(function()
		return HttpService:GetAsync(proxy(url)) 
	end)
	if success then 
		--return HttpService:JSONDecode(result) 
		return result 
	elseif table.find(whitelisted_errors, result) then 
		warn(result)
		return nil 
	else 
		warn(result) 
		task.wait(1) 
		if attempts > 1 then 
			return GET(url, attempts-1) 
		else 
			warn("max attempts reached") 
			return nil 
		end
	end
end

function search(id) 
	local info = GET("https://api.roblox.com/marketplace/productinfo?assetId="..id)
	if not info then return 1 end --id doesn't exist
	info = HttpService:JSONDecode(info)
	if info.AssetTypeId ~= 3 then return 2 end --id isn't a sound
	local CreatorID, Keyword = info.Creator.Id, info.Name 
	local pagesUrl = "https://search.roblox.com/catalog/json?CatalogContext=2&Category=9&CreatorID=%d&Keyword=%s&PageNumber=%d"
	local function pageSearch(num) 
		local assets = GET(pagesUrl:format(CreatorID, Keyword, num)) 
		return HttpService:JSONDecode(assets) 
	end
	local current = 1 --current page
	while true do 
		print("searching page "..current)
		local assets = pageSearch(current)
		if #assets == 0 then return 3 end --id is private 
		for _, asset in pairs(assets) do 
			if asset.AssetId == id then 
				return asset 
			end
		end
		current += 1
	end 
end

local errors = {"Invalid id", "Not an audio id", "Audio is private"}
local asset = search(id)

if tonumber(asset) then 
	print(errors[asset])
else 
	print(asset.Name.." audio url is: "..asset.AudioUrl)
end

In-game demo: Audio link fetcher - Roblox

18 Likes

UPDATE: I released a version that used to work for private audio as well(it uses website scraping instead of the SearchAPI)

--keep proxy and GET code from the other method
local id = 142376088

function cut(text, start, ending)
	return text:split(start)[2]:split(ending)[1]
end

function parseNameAndUrl(infoPage) 
	local name = cut(infoPage, "class=\"plugin-title\">", "</h3>")
	local url = cut(infoPage, "<a href=\"", "\" class=\"plugin-image\" >")
	return name, url 
end

function search(id) 
	local infoPage = GET("https://www.roblox.com/studio/plugins/info?assetId="..id) 
	if not infoPage then return 1 end --id doesn't exist 
	local asset = {}
	asset.Name, asset.AbsoluteUrl = parseNameAndUrl(infoPage) 
	local webpage = GET(asset.AbsoluteUrl) 
	if not webpage then return 2 end --id isn't a sound
	local urls = webpage:split("url=\"") 
	for _, url in pairs(urls) do 
		url = url:sub(1, url:find("\"")-1)
		if url:find("rbxcdn") then 
			asset.AudioUrl = url 
			return asset
		end 
	end
	return 2 --id isn't a sound
end

local errors = {"Audio doesn't exist", "This isn't an audio id"}
local asset = search(id)

if tonumber(asset) then 
	print(errors[asset])
else 
	print(asset.Name.." audio url is: "..asset.AudioUrl)
end

Both methods SearchAPI and website scrap can be found inside the game demo.

9 Likes

This is really cool! I would definitely use this in one of my projects!

1 Like

Audio that goes private after the 22nd of March will most likely not be playable on-site too according to the announcement (only metadata will remain), so this method likely won’t work after the 22nd of March rither.

4 Likes

Can confirm it unfortunately does not work any longer

2 Likes

It does work, For me at least, Ive got an explosion sound which after may 22 is non working, I use the script, then boom i got that explosion sound

1 Like

I assume the sound is less than 6 seconds, therefore it never got set to private by Roblox.

1 Like

It got, I was getting errors of please grant audio permission to be used in this place which i cannot configure due to i not having permission in my place, But also that audio is less than 6 second so idk

1 Like

This person is a bloody flipping legend. Thank you for your service soldier.

2 Likes

Or just use the BTROBLOX extension.

1 Like

I don’t believe that will work for anything more than 6 seconds anymore.

Any audio that’s longer than that will have the play button removed from the website, making it completely unplayable. Without the play button, getting the CDN link is more than likely impossible.

In the future, solutions might be thought of to get the CDN links (and there might even be some already). The only we can do right now is be patient, I think.

2 Likes

Umm yes there’s no play button but it does download a file that has no extension which could be added a .mp3 extension,I tried this on Music that builds which when i published turns out error to grant asset permision

2 Likes

It says it isnt an id, while it is?

Hello, looks like roblox removed something or i don’t know because its not working annymore.
I would like have help for fix that, if you know?

image