Python Script for Bulk Sound Permission Granting

I wrote this automation script, because of the absurd situation I was in (I needed to grant ~50 audio permissions and there was no way I was doing that manually).

Small How-To

This tutorial may demand some computer & python knowledge. If there will be the need, i might make a more in-depth and a user-friendly guide for this.

You might need to play with the time.sleep() times a little bit so that it works smoothly for you, but the setup is pretty simple:

You need:

  • One or more universe id’s.
  • One or more sound id’s. (if you need a convenient way to get them, look at the bottom of this post :slight_smile:)
  • Your Roblox cookie. (.ROBLOSECURITY).
  • Python 3
  • undetected-chromedriver and selenium Python modules installed.

Once you get these, just put them into the script. Here’s an example how that might look:
image

And you should be ready to run the script!

The script in question:

import undetected_chromedriver as uc
from selenium.webdriver.common.by import By
import time

universeIds = []
soundIds = []
roblosecurity = ""

if __name__ == '__main__':
    driver = uc.Chrome(headless=False,use_subprocess=False)
    driver.get('https://create.roblox.com/')

    driver.add_cookie({
        "name": ".ROBLOSECURITY",
        "value": roblosecurity,
        "domain": ".roblox.com",
    })

    time.sleep(2)

    driver.get("https://create.roblox.com/dashboard/creations")

    for sId in soundIds:
        print("Sound id:", sId)
        driver.get(f"https://create.roblox.com/dashboard/creations/marketplace/{sId}/permissions")

        time.sleep(2)

        input_element = driver.find_element(By.ID, "privateExperienceAccessId")
        button_element = driver.find_element(By.XPATH, '//button[text()="Add"]')

        for uId in universeIds:
            input_element.clear()
            input_element.send_keys(uId)
            time.sleep(1)
            
            if input_element.is_enabled():
                button_element.click()
            else:
                print("Waiting for #privateExperienceAccessId button. (Maybe increase the wait?)")
                time.sleep(5)

                if input_element.is_enabled():
                    button_element.click()
                    time.sleep(3)
                else:
                    time.sleep(1)
                    continue
            
        button_element = driver.find_element(By.XPATH, '//button[text()="Save changes"]')

        if not button_element.is_enabled():
            print("Button grayed out, waiting")
            time.sleep(5)

        if button_element.is_enabled():
            button_element.click()

        time.sleep(3)

    print("done")
    time.sleep(10)

A more convenient way of getting sound id’s

I’ve made a small Plugin, for getting all sound id’s of sounds (which are owned by the user) under a selected instance.

How does one use it? Select an instance in the explorer and use the Get Sound Id's button. This will print out all of the id’s found in the console.

-- by KernelDeveloper (https://github.com/370rokas/)

local selection = game:GetService("Selection")
local marketplace = game:GetService("MarketplaceService")
local studio = game:GetService("StudioService")
local https = game:GetService("HttpService")

local userId = studio:GetUserId()

function RemoveTableDupes(tab)
	local a = {}
	local res = {}
	for _,v in ipairs(tab) do
		if (not a[v]) then
			res[#res+1] = v
			a[v] = true
		end
	end
	return res
end

local toolbar = plugin:CreateToolbar("IDGatherer")

local meshIdBtn = toolbar:CreateButton("Get Mesh Id's", "Get all mesh id's from the selected model", "rbxassetid://4458901886")
meshIdBtn.ClickableWhenViewportHidden = false

local soundIdBtn = toolbar:CreateButton("Get Sound Id's", "Get all sound id's from the selected model", "rbxassetid://4458901886")
soundIdBtn.ClickableWhenViewportHidden = false

meshIdBtn.Click:Connect(function()
	local selectedObjects = selection:Get()

	if #selectedObjects > 0 then
		local MeshIds = {}

		for _,v in ipairs(selectedObjects) do
			local d = v:GetDescendants()
			for _,v0 in ipairs(d) do
				if v0:IsA("MeshPart") then
					local raw = v0.MeshId
					local assetId = string.match(raw, "%d+")

					if assetId ~= nil then
						local asset = marketplace:GetProductInfo(assetId)

						if asset.Creator.CreatorTargetId == userId then
							table.insert(MeshIds, asset.AssetId)
						end
					end
				end
			end
		end

		print("Done: ")
		print(https:JSONEncode(RemoveTableDupes(MeshIds)))
	else
		print("No selected models.")
	end
end)

soundIdBtn.Click:Connect(function()
	local userId = studio:GetUserId()
	local selectedObjects = selection:Get()

	if #selectedObjects > 0 then
		local MeshIds = {}

		for _,v in ipairs(selectedObjects) do
			local d = v:GetDescendants()
			for _,v0 in ipairs(d) do
				if v0:IsA("Sound") then
					local raw = v0.SoundId
					local assetId = string.match(raw, "%d+")

					if assetId ~= nil then
						local asset = marketplace:GetProductInfo(assetId)

						if asset.Creator.CreatorTargetId == userId then
							table.insert(MeshIds, asset.AssetId)
						end
					end
				end
			end
		end

		print("Done: ")
		print(https:JSONEncode(RemoveTableDupes(MeshIds)))
	else
		print("No selected models.")
	end
end)

Help, Bugs?

Feel free to report any bugs/errors or questions you may have in this thread. I will try, but I can’t promise that I will answer all of them :slight_smile:

In the future, I may clean the code up, set up a GitHub repo, etc, but idk… Anyways, enjoy :slight_smile: !

6 Likes

First of all, I want to thank you for sharing this tool. I have about 200+ sounds that I need to grant permissions to an experience, which obviously would be ridiculous to do one by one, especially by how slow the website load at times and the amount of clicks and scrolling each one requires. Finding this tool gave me a bit of hope, but I’m having an issue that is returning this error (Please note I replaced the paths with “…” for ease of viewing)

  File "...\main.py", line 18, in <module>
    driver = uc.Chrome(headless=False,use_subprocess=False)
  File "...\undetected_chromedriver\__init__.py", line 372, in __init__
    options.binary_location = (
  File "...\selenium\webdriver\chromium\options.py", line 52, in binary_location
    raise TypeError(self.BINARY_LOCATION_ERROR)
TypeError: Binary Location Must be a String

I’m not familiar with Python, so I’m not sure what I could be doing wrong. I did install the undetected-chromedriver and selenium modules as noted in the OP. Any idea what I could be doing wrong? I copied the code into a file, added my universe ids, sound ids, and added the cookie to a file where the .py is, then ran it in the command prompt.

Edit: After looking around for a while, I stumbled on the issue. I don’t have Chrome installed. I tried to make it work with Dragon, Edge and Brave, but I couldn’t succeed due to the WebDriver not recognizing the browser version on either. I had to install Chrome in the end, and there was an issue with one button not being recognized. “Save changes” should be “Save Changes”, that fixed the problem and it’s working on the background.

If I could suggest something, I’d say that, if it detects that the place with the universe id in the list of universes that are allowed to use the sound is already added, to simply skip the sound to the next one. I also had an issue with a red text where the universe details could not be fetch or something, and that made the permissions change fail. Perhaps it could detect that too and make it keep retrying until it succeeds?

Other than that, this script is a life saver. I can work on other things while it works in an automated manner. Thank you so much for sharing it.

1 Like

Hey, sorry for the late response.

No clue how to fix this one besides installing chrome. I found on the undetected-chromedriver GitHub, that if you dont want to install chrome, you can download chromium binaries manually and modify the line as such:

driver = uc.Chrome(options = options, browser_executable_path="/usr/bin/chromium", driver_executable_path="/tmp/chromedriver")

(yea ik its a linux-based thread but it shouldn’t be too far off on Windows too)

Sure, if I have time in the near future I’ll be sure to add that :slight_smile:

I’ll also look into that, if you manage to reproduce the issue, please send me the error message or the steps you took to get that error.

If you want, feel free to implement these features yourself :slight_smile:

P.S i’m pretty sure you can use chromedriver-py · PyPI to install the binaries for selenium, did you try that?

No clue how to fix this one besides installing chrome. I found on the undetected-chromedriver GitHub, that if you dont want to install chrome, you can download chromium binaries manually and modify the line as such

Oh, I already ended installing Chrome since I couldn’t find any other way to fix it. I couldn’t get it working with any of the other chromium based browsers I had. But yeah, effectively, it was the lack of Chrome what caused the issue.

I’ll also look into that, if you manage to reproduce the issue, please send me the error message or the steps you took to get that error.

Oh, I didn’t get an error message from Python itself, but the Roblox website. It was a red text but I didn’t notice it quick enough to take a snapshot of the error, and it already waited for long enough to move onto the next sound. It was some red text in the Roblox website, possibly caused by Roblox itself having a stutter. It wasn’t anything too major, but I figured it’d be nice for it to retry until succeeding instead of finding about it the hard way.

The only error I had from Python which prevented the script from executing was a typo, where the “Save Changes” was set to “Save changes”. Merely capitalizing the C solved it.

If you want, feel free to implement these features yourself :slight_smile:

I actually wanted to try, but Python and web stuff is outside of my knowledge, otherwise I’d have done that already, haha. It isn’t a big deal, though, merely a “nice to have” kind of thing.

P.S i’m pretty sure you can use chromedriver-py · PyPI to install the binaries for selenium, did you try that?

I tried undetected_chromedriver, I wasn’t familiar with that one. I’m guessing, since I already got Chrome installed, it’d be kinda moot to install these. I did try “undetected_edge” to see if I could make it work with Microsoft Edge, but it didn’t seem to help.

Again, it’s still a neat script that saved me tons of work. I can’t recommend it enough for anyone in a similar situation as I was. Thank you again for sharing it.

1 Like