-- LocalScript: Sound ID Ripper + Preview (with song title, colors, left thumbnail image + grouped by parent name + search bar + publisher + rbx link button) local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local MarketplaceService = game:GetService("MarketplaceService") local player = Players.LocalPlayer local playerGui = player:WaitForChild("PlayerGui") local workspace = game:GetService("Workspace") -- Create ScreenGui (forced above Roblox core UI) local screenGui = Instance.new("ScreenGui") screenGui.Name = "SoundRipperSmall" screenGui.ResetOnSpawn = false screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling screenGui.DisplayOrder = 2147483647 screenGui.IgnoreGuiInset = true screenGui.Parent = playerGui -- Main frame local mainFrame = Instance.new("Frame") mainFrame.Size = UDim2.new(0.36, 0, 0.60, 0) mainFrame.Position = UDim2.new(0.32, 0, 0.20, 0) mainFrame.BackgroundColor3 = Color3.fromRGB(0, 0, 0) mainFrame.BorderSizePixel = 0 mainFrame.ZIndex = 1000 mainFrame.Parent = screenGui local uiCorner = Instance.new("UICorner") uiCorner.CornerRadius = UDim.new(0, 8) uiCorner.Parent = mainFrame local title = Instance.new("TextLabel") title.Size = UDim2.new(1, 0, 0, 32) title.BackgroundColor3 = Color3.fromRGB(30, 30, 30) title.Text = "Sound Ripper • Click to copy • Play locally" title.TextColor3 = Color3.new(1,1,1) title.Font = Enum.Font.GothamBold title.TextSize = 15 title.ZIndex = 1001 title.Parent = mainFrame local titleCorner = Instance.new("UICorner") titleCorner.CornerRadius = UDim.new(0, 8) titleCorner.Parent = title -- Search bar local searchBox = Instance.new("TextBox") searchBox.Size = UDim2.new(1, -16, 0, 18) searchBox.Position = UDim2.new(0, 8, 0, 38) searchBox.BackgroundColor3 = Color3.fromRGB(20, 20, 20) searchBox.TextColor3 = Color3.new(1,1,1) searchBox.PlaceholderText = " Search title, ID or publisher..." searchBox.PlaceholderColor3 = Color3.fromRGB(160, 160, 180) searchBox.Font = Enum.Font.Gotham searchBox.TextSize = 14 searchBox.ClearTextOnFocus = false searchBox.TextXAlignment = Enum.TextXAlignment.Left searchBox.Text = "" searchBox.Parent = mainFrame local searchCorner = Instance.new("UICorner") searchCorner.CornerRadius = UDim.new(0, 6) searchCorner.Parent = searchBox -- Scrolling frame local scrollingFrame = Instance.new("ScrollingFrame") scrollingFrame.Size = UDim2.new(1, -12, 1, -80) scrollingFrame.Position = UDim2.new(0, 6, 0, 60) scrollingFrame.BackgroundTransparency = 1 scrollingFrame.ScrollBarThickness = 5 scrollingFrame.ScrollBarImageColor3 = Color3.fromRGB(100, 100, 120) scrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0) scrollingFrame.Parent = mainFrame local listLayout = Instance.new("UIListLayout") listLayout.Padding = UDim.new(0, 4) listLayout.SortOrder = Enum.SortOrder.LayoutOrder listLayout.Parent = scrollingFrame -- Refresh + Close buttons local refreshBtn = Instance.new("TextButton") refreshBtn.Size = UDim2.new(0, 70, 0, 26) refreshBtn.Position = UDim2.new(1, -105, 0, 4) refreshBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0) refreshBtn.Text = "Refresh" refreshBtn.TextColor3 = Color3.new(1,1,1) refreshBtn.Font = Enum.Font.GothamSemibold refreshBtn.TextSize = 13 refreshBtn.ZIndex = 1010 refreshBtn.Parent = mainFrame local btnCorner1 = Instance.new("UICorner") btnCorner1.CornerRadius = UDim.new(0, 5) btnCorner1.Parent = refreshBtn local closeBtn = Instance.new("TextButton") closeBtn.Size = UDim2.new(0, 26, 0, 26) closeBtn.Position = UDim2.new(1, -30, 0, 4) closeBtn.BackgroundColor3 = Color3.fromRGB(50, 50, 50) closeBtn.Text = "X" closeBtn.TextColor3 = Color3.new(1,1,1) closeBtn.Font = Enum.Font.GothamBold closeBtn.TextSize = 14 closeBtn.ZIndex = 1010 closeBtn.Parent = mainFrame local btnCorner2 = Instance.new("UICorner") btnCorner2.CornerRadius = UDim.new(0, 5) btnCorner2.Parent = closeBtn -- Playing sounds tracker local playingSounds = {} local soundToEntry = {} local productCache = {} -- Update canvas local function updateCanvasSize() task.wait() local contentHeight = listLayout.AbsoluteContentSize.Y scrollingFrame.CanvasSize = UDim2.new(0, 0, 0, contentHeight + 12) end -- Fast song info (cache) local function getSongInfo(soundId) local numericId = tonumber(soundId:match("%d+")) if not numericId then return "Unknown Title", "Unknown Publisher" end if productCache[numericId] then local info = productCache[numericId] return info.Name or "Unknown Title", info.Creator and info.Creator.Name or "Unknown Publisher" end local success, info = pcall(function() return MarketplaceService:GetProductInfo(numericId, Enum.InfoType.Asset) end) if success and info then productCache[numericId] = info return info.Name or "Unknown Title", info.Creator and info.Creator.Name or "Unknown Publisher" else return "Unknown Title", "Unknown Publisher" end end -- Thumbnail local function getThumbnailUrl(numericId) return numericId and ("rbxthumb://type=Asset&id=" .. numericId .. "&w=150&h=150") or nil end -- Create header local function createGroupHeader(parentName) local header = Instance.new("TextLabel") header.Size = UDim2.new(1, 0, 0, 21) header.BackgroundColor3 = Color3.fromRGB(40, 40, 40) header.Text = parentName header.TextColor3 = Color3.fromRGB(255, 255, 255) header.Font = Enum.Font.GothamBold header.TextSize = 15 header.TextXAlignment = Enum.TextXAlignment.Left header.TextWrapped = true header.Parent = scrollingFrame local hCorner = Instance.new("UICorner") hCorner.CornerRadius = UDim.new(0, 6) hCorner.Parent = header local padding = Instance.new("UIPadding") padding.PaddingLeft = UDim.new(0, 10) padding.PaddingTop = UDim.new(0, 5) padding.PaddingBottom = UDim.new(0, 5) padding.Parent = header return header end -- Add entry local function addSoundEntry(sound) if not sound:IsA("Sound") or sound.SoundId == "" then return end if soundToEntry[sound] then return end local songTitle, publisher = getSongInfo(sound.SoundId) local numericId = tonumber(sound.SoundId:match("%d+")) local thumbUrl = getThumbnailUrl(numericId) local parentName = (sound.Parent and sound.Parent.Name) or "Unknown" local entry = Instance.new("Frame") entry.Size = UDim2.new(1, 0, 0, 70) entry.BackgroundColor3 = Color3.fromRGB(30, 30, 30) entry.BorderSizePixel = 0 entry.Parent = scrollingFrame local corner = Instance.new("UICorner") corner.CornerRadius = UDim.new(0, 6) corner.Parent = entry local thumbImage = Instance.new("ImageLabel") thumbImage.Size = UDim2.new(0, 48, 0, 48) thumbImage.Position = UDim2.new(0, 8, 0.5, -24) thumbImage.BackgroundColor3 = Color3.fromRGB(60, 60, 70) thumbImage.BackgroundTransparency = 0.3 thumbImage.Image = thumbUrl or "" thumbImage.ScaleType = Enum.ScaleType.Fit thumbImage.ResampleMode = Enum.ResamplerMode.Pixelated thumbImage.Parent = entry local thumbCorner = Instance.new("UICorner") thumbCorner.CornerRadius = UDim.new(0, 6) thumbCorner.Parent = thumbImage if not thumbUrl then local placeholder = Instance.new("TextLabel") placeholder.Size = UDim2.new(1, 0, 1, 0) placeholder.BackgroundTransparency = 1 placeholder.Text = "?" placeholder.TextColor3 = Color3.fromRGB(255, 255, 255) placeholder.Font = Enum.Font.GothamBold placeholder.TextSize = 28 placeholder.Parent = thumbImage end local titleLabel = Instance.new("TextLabel") titleLabel.Size = UDim2.new(0.75, 0, 0, 20) titleLabel.Position = UDim2.new(0, 64, 0.08, 0) titleLabel.BackgroundTransparency = 1 titleLabel.Text = songTitle titleLabel.TextColor3 = Color3.fromRGB(255, 0, 0) titleLabel.Font = Enum.Font.GothamBold titleLabel.TextSize = 14 titleLabel.TextXAlignment = Enum.TextXAlignment.Left titleLabel.TextTruncate = Enum.TextTruncate.AtEnd titleLabel.Parent = entry local pubLabel = Instance.new("TextLabel") pubLabel.Size = UDim2.new(0.75, 0, 0, 16) pubLabel.Position = UDim2.new(0, 64, 0.30, 0) pubLabel.BackgroundTransparency = 1 pubLabel.Text = "by " .. publisher pubLabel.TextColor3 = Color3.fromRGB(200, 200, 200) pubLabel.Font = Enum.Font.Gotham pubLabel.TextSize = 12 pubLabel.TextXAlignment = Enum.TextXAlignment.Left pubLabel.TextTruncate = Enum.TextTruncate.AtEnd pubLabel.Parent = entry local nameLabel = Instance.new("TextLabel") nameLabel.Size = UDim2.new(0.75, 0, 0, 16) nameLabel.Position = UDim2.new(0, 64, 0.5, 0) nameLabel.BackgroundTransparency = 1 nameLabel.Text = parentName nameLabel.TextColor3 = Color3.fromRGB(200, 200, 100) nameLabel.Font = Enum.Font.GothamSemibold nameLabel.TextSize = 12 nameLabel.TextXAlignment = Enum.TextXAlignment.Left nameLabel.TextTruncate = Enum.TextTruncate.AtEnd nameLabel.Parent = entry local idLabel = Instance.new("TextLabel") idLabel.Size = UDim2.new(0.75, 0, 0, 14) idLabel.Position = UDim2.new(0, 64, 0.67, 0) idLabel.BackgroundTransparency = 1 idLabel.Text = sound.SoundId idLabel.TextColor3 = Color3.fromRGB(170, 170, 190) idLabel.Font = Enum.Font.Code idLabel.TextSize = 11 idLabel.TextXAlignment = Enum.TextXAlignment.Left idLabel.TextWrapped = true idLabel.Parent = entry local copyBtn = Instance.new("TextButton") copyBtn.Size = UDim2.new(0, 48, 0, 18) copyBtn.Position = UDim2.new(1, -110, 0.6, -14) copyBtn.BackgroundColor3 = Color3.fromRGB(000, 000, 000) copyBtn.Text = "Copy" copyBtn.TextColor3 = Color3.new(1,1,1) copyBtn.Font = Enum.Font.GothamSemibold copyBtn.TextSize = 12 copyBtn.ZIndex = 1010 copyBtn.Parent = entry local copyCorner = Instance.new("UICorner") copyCorner.CornerRadius = UDim.new(0, 4) copyCorner.Parent = copyBtn copyBtn.MouseButton1Click:Connect(function() if setclipboard then local numericId = sound.SoundId:match("%d+") setclipboard(numericId or sound.SoundId) -- only the number copyBtn.Text = "Copied!" task.delay(1, function() copyBtn.Text = "Copy" end) end end) local rbxBtn = Instance.new("TextButton") rbxBtn.Size = UDim2.new(0, 38, 0, 18) rbxBtn.Position = UDim2.new(1, -158, 0.6, -14) rbxBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0) rbxBtn.Text = "Link" rbxBtn.TextColor3 = Color3.new(1,1,1) rbxBtn.Font = Enum.Font.GothamSemibold rbxBtn.TextSize = 13 rbxBtn.ZIndex = 1010 rbxBtn.Parent = entry local rbxCorner = Instance.new("UICorner") rbxCorner.CornerRadius = UDim.new(0, 4) rbxCorner.Parent = rbxBtn rbxBtn.MouseButton1Click:Connect(function() local numericId = tonumber(sound.SoundId:match("%d+")) or 0 local assetUrl = "https://create.roblox.com/store/asset/" .. numericId if setclipboard then setclipboard(assetUrl) rbxBtn.Text = "✓" task.delay(1.5, function() if rbxBtn and rbxBtn.Parent then rbxBtn.Text = "rbx" end end) else game:GetService("StarterGui"):SetCore("SendNotification", { Title = "rbx link", Text = "Link (manual copy):\n" .. assetUrl, Duration = 6 }) end end) local playBtn = Instance.new("TextButton") playBtn.Size = UDim2.new(0, 28, 0, 18) playBtn.Position = UDim2.new(1, -48, 0.6, -14) playBtn.BackgroundColor3 = Color3.fromRGB(0, 255, 0) playBtn.Text = "▶" playBtn.TextColor3 = Color3.new(1,1,1) playBtn.Font = Enum.Font.GothamBold playBtn.TextSize = 20 playBtn.Parent = entry local playCorner = Instance.new("UICorner") playCorner.CornerRadius = UDim.new(0, 4) playCorner.Parent = playBtn local stopBtn = Instance.new("TextButton") stopBtn.Size = UDim2.new(0, 28, 0, 18) stopBtn.Position = UDim2.new(1, -48, 0.6, -14) stopBtn.BackgroundColor3 = Color3.fromRGB(190, 60, 60) stopBtn.Text = "■" stopBtn.TextColor3 = Color3.new(1,1,1) stopBtn.Font = Enum.Font.GothamBold stopBtn.TextSize = 20 stopBtn.Visible = false stopBtn.Parent = entry local stopCorner = Instance.new("UICorner") stopCorner.CornerRadius = UDim.new(0, 4) stopCorner.Parent = stopBtn local currentSound = nil local isAttempting = false local function stopCurrent() if currentSound then pcall(function() currentSound:Stop() end) currentSound:Destroy() currentSound = nil end playBtn.Visible = true stopBtn.Visible = false playingSounds[entry] = nil playBtn.Text = "▶" end playBtn.MouseButton1Click:Connect(function() if isAttempting then return end isAttempting = true playBtn.BackgroundTransparency = 0.5 playBtn.Text = "🔄" stopCurrent() local tempSound = Instance.new("Sound") tempSound.SoundId = sound.SoundId tempSound.Volume = 0.7 tempSound.Looped = false local playParent = workspace.CurrentCamera or playerGui tempSound.Parent = playParent pcall(function() tempSound:Load() end) local loaded = false local startTime = tick() while tick() - startTime < 4 do if tempSound.IsLoaded then loaded = true break end task.wait(0.03) end if not loaded then idLabel.TextColor3 = Color3.fromRGB(255, 255, 255) playBtn.BackgroundColor3 = Color3.fromRGB(255, 0, 0) playBtn.Text = "X" playBtn.BackgroundTransparency = 0 task.delay(1.5, function() if playBtn and playBtn.Parent then playBtn.Text = "▶" playBtn.BackgroundColor3 = Color3.fromRGB(0, 255, 0) end end) pcall(function() tempSound:Destroy() end) isAttempting = false return end local playSuccess = pcall(function() tempSound:Play() end) if playSuccess then currentSound = tempSound playBtn.Visible = false stopBtn.Visible = true playingSounds[entry] = {sound = tempSound} task.spawn(function() pcall(function() tempSound.Ended:Wait() end) task.wait(0.1) if currentSound == tempSound then stopCurrent() end end) else idLabel.TextColor3 = Color3.fromRGB(255, 80, 80) playBtn.Text = "X" playBtn.BackgroundColor3 = Color3.fromRGB(120, 40, 40) task.delay(1.5, function() if playBtn then playBtn.Text = "▶" playBtn.BackgroundColor3 = Color3.fromRGB(90, 130, 210) end end) pcall(function() tempSound:Destroy() end) end isAttempting = false playBtn.BackgroundTransparency = 0 if playBtn.Visible then playBtn.Text = "▶" end end) stopBtn.MouseButton1Click:Connect(stopCurrent) soundToEntry[sound] = entry end -- Fast targeted scan local function scanAllSounds() -- Cleanup playing sounds for _, data in pairs(playingSounds) do if data and data.sound then pcall(function() data.sound:Stop() end) data.sound:Destroy() end end playingSounds = {} -- Clear old UI for _, child in scrollingFrame:GetChildren() do if child:IsA("Frame") or child:IsA("TextLabel") then child:Destroy() end end soundToEntry = {} local count = 0 local groups = {} -- Fast targets local targets = { workspace, player.Character, player:FindFirstChild("Backpack"), } for _, service in {game.ReplicatedStorage} do if service then table.insert(targets, service) end end for _, target in ipairs(targets) do if target then for _, obj in ipairs(target:GetDescendants()) do if obj:IsA("Sound") and obj.SoundId and obj.SoundId ~= "" then local parentName = (obj.Parent and obj.Parent.Name) or "Unknown" groups[parentName] = groups[parentName] or {} table.insert(groups[parentName], obj) count += 1 end end end end -- Sort: MusicHolder first, then Handle-related, then alphabetical local sortedParents = {} for p in pairs(groups) do table.insert(sortedParents, p) end table.sort(sortedParents, function(a, b) local aLower = a:lower() local bLower = b:lower() -- MusicHolder on absolute top if aLower == "musicholder" and bLower ~= "musicholder" then return true end if bLower == "musicholder" and aLower ~= "musicholder" then return false end -- Then Handle-related local aIsHandle = aLower:find("handle") or aLower:find("boombox") or aLower:find("radio") or aLower:find("tool") local bIsHandle = bLower:find("handle") or bLower:find("boombox") or bLower:find("radio") or bLower:find("tool") if aIsHandle and not bIsHandle then return true end if not aIsHandle and bIsHandle then return false end return aLower < bLower end) -- Build UI for _, parentName in ipairs(sortedParents) do createGroupHeader(parentName) for _, sound in ipairs(groups[parentName]) do addSoundEntry(sound) end end title.Text = "RH S0UND R1PP3R X • Found: " .. count updateCanvasSize() end -- GUI loads first → initial fast scan task.defer(function() title.Text = "RH S0UND R1PP3R X • Scanning..." scanAllSounds() end) -- Manual refresh refreshBtn.MouseButton1Click:Connect(function() title.Text = "RH S0UND R1PP3R X • Refreshing..." scanAllSounds() end) -- Real-time add (no removal) game.DescendantAdded:Connect(function(desc) if desc:IsA("Sound") and desc.SoundId and desc.SoundId ~= "" then addSoundEntry(desc) title.Text = "Sound Ripper • Found: " .. #scrollingFrame:GetChildrenOfClass("Frame") updateCanvasSize() end end) -- LIVE SEARCH FILTERING local function filterEntries() local searchText = searchBox.Text:lower() if searchText == "" then for _, child in scrollingFrame:GetChildren() do if child:IsA("Frame") or child:IsA("TextLabel") then child.Visible = true end end title.Text = "Sound Ripper • Found: " .. #scrollingFrame:GetChildrenOfClass("Frame") updateCanvasSize() return end for _, child in scrollingFrame:GetChildren() do if child:IsA("Frame") or child:IsA("TextLabel") then child.Visible = false end end local visibleCount = 0 local currentParent = nil for _, child in scrollingFrame:GetChildren() do if child:IsA("TextLabel") then currentParent = child.Text child.Visible = false elseif child:IsA("Frame") then local titleLbl = child:FindFirstChildOfClass("TextLabel") local idLbl = child:FindFirstChild("idLabel", true) local pubLbl = child:FindFirstChild("pubLabel", true) local titleText = titleLbl and titleLbl.Text:lower() or "" local idText = idLbl and idLbl.Text:lower() or "" local pubText = pubLbl and pubLbl.Text:lower() or "" if titleText:find(searchText, 1, true) or idText:find(searchText, 1, true) or pubText:find(searchText, 1, true) then child.Visible = true visibleCount += 1 if currentParent then for _, h in scrollingFrame:GetChildren() do if h:IsA("TextLabel") and h.Text == currentParent then h.Visible = true break end end end end end end title.Text = "RH S0UND R1PP3R X • Found: " .. visibleCount .. " (filtered)" updateCanvasSize() end searchBox:GetPropertyChangedSignal("Text"):Connect(filterEntries) closeBtn.MouseButton1Click:Connect(function() for _, data in pairs(playingSounds) do if data and data.sound then pcall(function() data.sound:Stop() end) data.sound:Destroy() end end screenGui:Destroy() end) -- Smooth dragging local dragging = false local dragStart = nil local startPos = nil mainFrame.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position startPos = mainFrame.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) UserInputService.InputChanged:Connect(function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then local delta = input.Position - dragStart mainFrame.Position = UDim2.new( startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y ) end end) listLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(updateCanvasSize)