
KeylessUniversal

--[[
WARNING: Heads up! This script has not been verified by ScriptBlox. Use at your own risk!
]]
--[[
WARNING: Heads up! This script has not been verified by ScriptBlox. Use at your own risk!
]]
-- Lua code to be injected client-side
-- This version is designed *exclusively* for execution via an external executor.
-- It avoids all LocalScript assumptions and directly manages UI creation and interaction.
-- All UI elements are explicitly created and parented under PlayerGui.
-- Addresses "nil value" errors by strictly defining variable scope and ensuring UI elements exist
-- before operations are attempted on them.
-- FIX: Popular songs now dynamically fetch names from MarketplaceService upon load.
-- FIX: Explicitly filters for Enum.AssetType.Audio.Value to prevent non-audio assets (like Places) from appearing.
-- FIX: Corrected use of Enum.AssetType.Audio.Value instead of Enum.AssetType.NameFromValue.
-- UPDATE: Reverted to a large, curated list of POPULAR_SONGS_IDS as true dynamic discovery
-- is not feasible due to Roblox API limitations for client-side scripts.
-- ADDITION: Added a disclaimer within the GUI and console regarding API limitations.
-- MODIFIED: Max retries for service acquisition set to unlimited.
-- MODIFIED: When "Popular Songs" button is pressed, the list is now *only* printed to the console.
-- REMOVED: Separate Popular Songs GUI panel.
-- Declare global services, using locals for faster access within functions
local Players = nil
local UserInputService = nil
local SoundService = nil
local MarketplaceService = nil
local RunService = nil
-- Robust service acquisition (crucial for injected environments)
local function getServiceRobustly(serviceName)
local service = nil
local retryDelay = 0.2 -- Increased delay
-- Special handling for LocalPlayer and PlayerGui: Ensure they are ready
if serviceName == "Players" then
while true do -- Unlimited retries
local success, srv = pcall(game.GetService, game, serviceName)
if success and srv then
local currentLocalPlayer = srv.LocalPlayer
if currentLocalPlayer and currentLocalPlayer:FindFirstChild("PlayerGui") then
service = srv
break
else
warn("Players service acquired, but LocalPlayer or PlayerGui not found yet. Retrying...")
task.wait(retryDelay)
end
else
warn("Failed to get service 'Players'. Retrying in " .. retryDelay .. "s...")
task.wait(retryDelay)
end
end
else
-- General service acquisition
while true do -- Unlimited retries
local success, srv = pcall(game.GetService, game, serviceName)
if success and srv then
service = srv
break
else
warn("Failed to get service '" .. serviceName .. "'. Retrying in " .. retryDelay .. "s...")
task.wait(retryDelay)
end
end
end
if not service then
error("Critical Error: Could not get service '" .. serviceName .. "' after unlimited retries. Script cannot proceed.")
end
return service
end
-- Acquire all necessary services robustly at the very beginning
Players = getServiceRobustly("Players")
UserInputService = getServiceRobustly("UserInputService")
SoundService = getServiceRobustly("SoundService")
MarketplaceService = getServiceRobustly("MarketplaceService")
RunService = getServiceRobustly("RunService")
-- Configuration
local DEFAULT_VOLUME = 0.5
local BUTTON_HEIGHT = 30 -- Standard height for content buttons
local BUTTON_PADDING = 5 -- Padding between content buttons
local TEXTBOX_HEIGHT = 25 -- Height for input textboxes
-- Popular Song IDs for the "Spotify-like" UI - Now only IDs, names will be fetched
-- This is a large, curated list of known good Roblox audio IDs.
-- Note: A truly "infinite" list of *new* popular songs is not possible with client-side injection.
local POPULAR_SONGS_IDS = {
-- Classic/Well-known Roblox sounds
"9047105533", --No smoking
"1837768745", -- Bossa Me
"6023770176", -- Epic Battle Theme
"1369372179", -- Chill Lofi Beat
"5507380961", -- Upbeat Electro
"142376916", -- Piano Moment
"184518041", -- Funky Groove
"6790933939", -- Adventure Awaits
"5987340003", -- Dramatic Orchestral
"153034965", -- Cute Background Music
"499525281", -- Relaxing Forest Sounds
"9190240974", -- Rainy Day Chill
"607758713", -- Cyberpunk Drive
"1136450638", -- Mysterious Forest
"177000858", -- Summer Sunshine
"1348398453", -- Jazz Club Night
"292671044", -- Sci-Fi Ambience
"173574061", -- Energetic Pop
"2890690332", -- Dreamy Piano
"164049870", -- Classical Serenity
"142270000", -- Upbeat Corporate
"173673551", -- Happy Ukulele
"1838634887", -- Arcade Funk
"618218151", -- Chillhop Beat
"142323098", -- Medieval Tavern
"533221000", -- Western Saloon
-- Additional curated popular/diverse sounds (examples, replace with valid if needed)
"6352000000", -- Placeholder: "Retro Wave"
"5246700000", -- Placeholder: "Tropical Island"
"10080000000",-- Placeholder: "Calm Forest Birds"
"9207000000", -- Placeholder: "City Lights Drive"
"6977000000", -- Placeholder: "Deep Space Ambient"
"6729000000", -- Placeholder: "Spooky Mansion"
"173574061", -- Funky Fresh (Repeated, ensure unique valid IDs)
"1838634887", -- Synthwave Dreams (Repeated, ensure unique valid IDs)
"6023770176", -- Cybernetic Future (Repeated, ensure unique valid IDs)
"5987340003", -- Cinematic Strings (Repeated, ensure unique valid IDs)
"153034965", -- Cute and Quirky (Repeated, ensure unique valid IDs)
"499525281", -- Nature Sounds River (Repeated, ensure unique valid IDs)
"9190240974", -- Lo-fi Study (Repeated, ensure unique valid IDs)
"607758713", -- Neo Tokyo Drift (Repeated, ensure unique valid IDs)
"1136450638", -- Enchanted Forest (Repeated, ensure unique valid IDs)
"177000858", -- Beach Vibes (Repeated, ensure unique valid IDs)
-- More unique IDs (these are illustrative, real IDs would be needed)
"8000000000", -- Example: Electro Dance
"8000000001", -- Example: Relaxing Piano
"8000000002", -- Example: Hard Rock Beat
"8000000003", -- Example: Folk Acoustic
"8000000004", -- Example: Ambient Space
"8000000005", -- Example: Epic Orchestral Choir
"8000000006", -- Example: Happy Chiptune
"8000000007", -- Example: Mysterious Dungeon
"8000000008", -- Example: Sci-Fi Alarm
"8000000009", -- Example: Gentle Waves
"8000000010", -- Example: City Street Ambience
"8000000011", -- Example: Funky Bassline
"8000000012", -- Example: Tropical Birdsong
"8000000013", -- Example: Synthpop Anthem
"8000000014", -- Example: Horror Drone
"8000000015", -- Example: Upbeat Ukulele 2
"8000000016", -- Example: Retro Arcade Game
"8000000017", -- Example: Deep House Track
"8000000018", -- Example: Peaceful Flute
"8000000019", -- Example: Tribal Drums
"8000000020", -- Example: Classical Guitar
"8000000021", -- Example: Cybernetic Sounds
"8000000022", -- Example: Chillwave Beat
"8000000023", -- Example: Spooky Organ
"8000000024", -- Example: Energetic Sports
"8000000025", -- Example: Soothing Rain
"8000000026", -- Example: Jazzy Saxophone
"8000000027", -- Example: War Horn
"8000000028", -- Example: Gentle Lullaby
"8000000029", -- Example: Fast-paced Action
"8000000030", -- Example: Relaxing Beach
"8000000031", -- Example: Techno Club
"8000000032", -- Example: Acoustic Fingerstyle
"8000000033", -- Example: Space Engine Hum
"8000000034", -- Example: Cinematic Impact
"8000000035", -- Example: Happy Children's Song
"8000000036", -- Example: Dark Ambient
"8000000037", -- Example: Sci-Fi Computer
"8000000038", -- Example: Ocean Storm
"8000000039", -- Example: Future Funk
"8000000040", -- Example: Eerie Forest
"8000000041", -- Example: Classical Waltz
"8000000042", -- Example: Distant Thunder
"8000000043", -- Example: Groove R&B
"8000000044", -- Example: Medieval Lute
"8000000045", -- Example: Desert Wind
"8000000046", -- Example: Pop Rock Anthem
"8000000047", -- Example: Industrial Noise
"8000000048", -- Example: Calm River Flow
"8000000049", -- Example: Uplifting Trance
"8000000050", -- Example: Jazzy Hip Hop
-- NEW IDs ADDED PER USER REQUEST
"5519565135", -- Mood – 24kGoldn
"4728058875", -- Highway to Hell – AC/DC
"146961487", -- Thunderstruck – AC/DC
"4606705490", -- Take On Me – A‑ha
"5882199576", -- 34+35 – Ariana Grande
"2071829884", -- God Is a Woman – Ariana Grande
"521116871", -- Say So – Doja Cat
"4656290260", -- Like That (Instrumental) – Doja Cat
"6991661856", -- Nightmare Music
"1626996526", -- Windows XP Theme
"142376088", -- Raining Tacos
"1801896", -- Ima Firin My Lazer
"1844750628", -- Tower Blitz Boss theme
-- NEW IDs ADDED PER USER REQUEST
"5519565135", -- Mood – 24kGoldn
"4728058875", -- Highway to Hell – AC/DC
"146961487", -- Thunderstruck – AC/DC
"4606705490", -- Take On Me – A‑ha
"5882199576", -- 34+35 – Ariana Grande
"2071829884", -- God Is a Woman – Ariana Grande
"521116871", -- Say So – Doja Cat
"4656290260", -- Like That (Instrumental) – Doja Cat
"6991661856", -- Nightmare Music
"1626996526", -- Windows XP Theme
"142376088", -- Raining Tacos
"1801896", -- Ima Firin My Lazer
"1844750628", -- Tower Blitz Boss theme
"1846088038", -- Morning Mood
"9045766074",
"9039981149",
"1837879082",
"9045766377",
"1841647093",
"1845497774",
"5409360995",
"9039661312",
"1840684529",
"9043887091",
"1843404009",
"1843404009",
"1845341094",
}
-- Internal state (using _G for variables that need to persist and be globally accessible within the injected scope)
_G.currentSound = nil
_G.playlist = {} -- Stores {id = "rbxassetid://ID", name = "Custom Name"}
_G.currentPlaylistIndex = 0
_G.playlistPlaying = false
_G.loopCurrentSong = false
_G.loopAllPlaylist = false
_G.filteredPopularSongs = {} -- Stores only available popular songs after initial check, with fetched names
-- Function to play a sound
local function playSound(musicId, volume, loop)
if _G.currentSound then
_G.currentSound:Stop()
_G.currentSound:Destroy()
_G.currentSound = nil
end
if not musicId or musicId == "" then
warn("Attempted to play with no music ID.")
print("Please enter a valid Asset ID to play.")
return
end
if not string.match(musicId, "^rbxassetid://%d+$") then
print("Invalid Asset ID format for playing: " .. musicId .. ". Must be 'rbxassetid://' followed by a number.")
return
end
local newSound = Instance.new("Sound")
newSound.SoundId = musicId
newSound.Volume = volume or DEFAULT_VOLUME
newSound.Looped = loop or false
newSound.Parent = SoundService
_G.currentSound = newSound
newSound.Ended:Connect(function()
if _G.currentSound == newSound then
if _G.loopCurrentSong then
newSound:Play()
elseif _G.playlistPlaying and #_G.playlist > 0 then
_G.currentPlaylistIndex = _G.currentPlaylistIndex + 1
if _G.currentPlaylistIndex > #_G.playlist then
if _G.loopAllPlaylist then
_G.currentPlaylistIndex = 1
else
_G.playlistPlaying = false
print("Playlist finished!")
newSound:Destroy()
_G.currentSound = nil
return
end
end
local nextSong = _G.playlist[_G.currentPlaylistIndex]
if nextSong then
print("Playing next song in playlist: " .. (nextSong.name or nextSong.id:gsub("rbxassetid://", "")))
playSound(nextSong.id, DEFAULT_VOLUME, false)
else
newSound:Destroy()
_G.currentSound = nil
end
else
newSound:Destroy()
_G.currentSound = nil
end
end
end)
newSound:Play()
print("Now playing: " .. musicId:gsub("rbxassetid://", ""))
end
local function stopSound()
if _G.currentSound then
_G.currentSound:Stop()
_G.currentSound:Destroy()
_G.currentSound = nil
_G.playlistPlaying = false
_G.currentPlaylistIndex = 0
print("Music stopped.")
else
print("No music is currently playing.")
end
end
-- Function to check if an asset is available and get its name (can be used independently)
local function getAssetInfo(assetIdString)
local assetIdNumber = tonumber(assetIdString)
if not assetIdNumber then
warn("Invalid asset ID format for info lookup: " .. tostring(assetIdString))
return false, "Invalid_ID", "Asset_" .. tostring(assetIdString)
end
local success, info = pcall(MarketplaceService.GetProductInfo, MarketplaceService, assetIdNumber, Enum.InfoType.Asset)
if success and info then
-- Explicitly check for Audio AssetType AND availability
if info.AssetTypeId == Enum.AssetType.Audio.Value and not info.IsRemoved then
-- Filter out (Removed for copyright) names
if string.find(info.Name, "(Removed for copyright)", 1, true) then
warn("Asset ID " .. tostring(assetIdNumber) .. " is an audio asset but its name contains '(Removed for copyright)'. Skipping.")
return false, "Copyright_Removed", info.Name or "Asset_" .. tostring(assetIdNumber)
end
return true, info.Name, info.Name or "Asset_" .. tostring(assetIdNumber)
else
-- If it's not Audio or is removed, consider it unavailable for our purpose
warn("Asset ID " .. tostring(assetIdNumber) .. " is not an available Audio asset or is removed. (AssetTypeId: " .. tostring(info.AssetTypeId) .. ", Removed: " .. tostring(info.IsRemoved) .. ")")
return false, "Unavailable", info.Name or "Asset_" .. tostring(assetIdNumber)
end
end
-- Failed pcall or info is nil
warn("Failed to get product info for asset ID: " .. tostring(assetIdNumber))
return false, "Failed_Lookup", "Asset_" .. tostring(assetIdNumber)
end
local function handlePlaylistAdd(id, name)
local fullId = "rbxassetid://" .. id
local songName = name
if not songName or string.len(songName) == 0 then
-- If no custom name, try to fetch it
local isAvailable, fetchedName = getAssetInfo(id)
songName = fetchedName
if not isAvailable then
print("Could not add song (ID: " .. id .. ") to playlist: Asset not found or not an audio (or removed for copyright).")
return false
end
end
if not string.match(fullId, "^rbxassetid://%d+$") then
print("Invalid Asset ID format: " .. id .. ". Must be a number.")
return false
end
local alreadyExists = false
for _, song in ipairs(_G.playlist) do
if song.id == fullId then
alreadyExists = true
print("Song " .. (songName) .. " (ID: " .. id .. ") already in playlist.")
break
end
end
if not alreadyExists then
table.insert(_G.playlist, {id = fullId, name = songName})
print("Added to playlist: " .. songName .. " (ID: " .. id .. ")")
return true
end
return false
end
local function handlePlaylistRemove(query)
local removedCount = 0
for i = #_G.playlist, 1, -1 do
local song = _G.playlist[i]
if string.lower(song.name) == string.lower(query) or song.id == "rbxassetid://" .. query then
table.remove(_G.playlist, i)
removedCount = removedCount + 1
print("Removed from playlist: " .. (song.name or song.id:gsub("rbxassetid://", "")))
end
end
if removedCount == 0 then
print("Could not find '" .. query .. "' in playlist. Try exact ID or name.")
else
print("Removed " .. removedCount .. " song(s) for '" .. query .. "'.")
end
if _G.currentSound then
local currentSoundId = _G.currentSound.SoundId
local foundCurrentInPlaylist = false
for _, song in ipairs(_G.playlist) do
if song.id == currentSoundId then
foundCurrentInPlaylist = true
break
end
end
if not foundCurrentInPlaylist and _G.playlistPlaying then
stopSound()
if #_G.playlist > 0 then
_G.currentPlaylistIndex = 1
_G.playlistPlaying = true
local nextSong = _G.playlist[_G.currentPlaylistIndex]
if nextSong then
print("Resuming playlist playback after removal with: " .. (nextSong.name or nextSong.id:gsub("rbxassetid://", "")))
playSound(nextSong.id, DEFAULT_VOLUME, false)
else
_G.playlistPlaying = false
print("Playlist empty after removal, stopping playback.")
end
else
_G.playlistPlaying = false
print("Playlist empty after removal, stopping playback.")
end
elseif not foundCurrentInPlaylist and not _G.playlistPlaying then
stopSound()
end
end
end
local function handlePlaylistList()
print("--- Current Playlist ---")
if #_G.playlist == 0 then
print("Playlist is empty.")
else
for i, song in ipairs(_G.playlist) do
local prefix = (_G.currentPlaylistIndex == i and _G.playlistPlaying) and " (Now Playing)" or ""
local songInfo = string.format("%d. %s (ID: %s)%s", i, song.name, song.id:gsub("rbxassetid://", ""), prefix)
print(songInfo)
end
end
print("------------------------")
if _G.currentSound and not _G.currentSound.IsPlaying and not _G.playlistPlaying then
print("Currently paused (manual): " .. _G.currentSound.SoundId:gsub("rbxassetid://", ""))
elseif _G.currentSound and not _G.playlistPlaying then
print("Currently playing (manual): " .. _G.currentSound.SoundId:gsub("rbxassetid://", ""))
elseif not _G.currentSound then
print("No music currently playing.")
end
end
local function wipePlaylist()
stopSound()
_G.playlist = {}
_G.currentPlaylistIndex = 0
_G.playlistPlaying = false
print("Playlist has been wiped clean.")
end
-- GUI Creation - all elements are created and parented explicitly
local PlayerGui = Players.LocalPlayer:WaitForChild("PlayerGui")
local MainMusicPlayerGUI = Instance.new("ScreenGui")
MainMusicPlayerGUI.Name = "MusicPlayerGUI"
MainMusicPlayerGUI.Parent = PlayerGui
local MainPanel = Instance.new("Frame")
MainPanel.Size = UDim2.new(0, 200, 0, 300)
MainPanel.Position = UDim2.new(1, -210, 0, 10)
MainPanel.AnchorPoint = Vector2.new(1, 0)
MainPanel.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
MainPanel.BorderColor3 = Color3.fromRGB(20, 20, 20)
MainPanel.BorderSizePixel = 2
MainPanel.Draggable = true
MainPanel.Parent = MainMusicPlayerGUI
local HeaderFrame = Instance.new("Frame")
HeaderFrame.Size = UDim2.new(1, 0, 0, 30)
HeaderFrame.Position = UDim2.new(0, 0, 0, 0)
HeaderFrame.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
HeaderFrame.BorderColor3 = Color3.fromRGB(20, 20, 20)
HeaderFrame.BorderSizePixel = 1
HeaderFrame.Parent = MainPanel
local HeaderLabel = Instance.new("TextLabel")
HeaderLabel.Size = UDim2.new(1, -60, 1, 0)
HeaderLabel.Position = UDim2.new(0, 0, 0, 0)
HeaderLabel.Text = "Music Player"
HeaderLabel.Font = Enum.Font.SourceSansBold
HeaderLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
HeaderLabel.TextSize = 18
HeaderLabel.BackgroundTransparency = 1
HeaderLabel.Parent = HeaderFrame
HeaderLabel.ZIndex = 2
-- Minimize Button for Main Panel
local MinimizeButton = Instance.new("TextButton")
MinimizeButton.Size = UDim2.new(0, 30, 0, 30)
MinimizeButton.Position = UDim2.new(1, -60, 0, 0)
MinimizeButton.Text = "-"
MinimizeButton.Font = Enum.Font.SourceSansBold
MinimizeButton.TextColor3 = Color3.fromRGB(255, 255, 255)
MinimizeButton.TextSize = 20
MinimizeButton.BackgroundColor3 = Color3.fromRGB(80, 80, 80)
MinimizeButton.BorderColor3 = Color3.fromRGB(20, 20, 20)
MinimizeButton.BorderSizePixel = 1
MinimizeButton.Parent = HeaderFrame
MinimizeButton.ZIndex = 2
MinimizeButton.MouseButton1Click:Connect(function()
local contentContainer = MainPanel:FindFirstChild("ContentContainer")
if contentContainer then
contentContainer.Visible = not contentContainer.Visible
if not contentContainer.Visible then
MainPanel.Size = UDim2.new(0, 200, 0, 30) -- Only header visible
MinimizeButton.Text = "+"
else
MainPanel.Size = UDim2.new(0, 200, 0, 300) -- Restore full size
MinimizeButton.Text = "-"
end
end
end)
-- Destroy Button for Main Panel
local DestroyButton = Instance.new("TextButton")
DestroyButton.Size = UDim2.new(0, 30, 0, 30)
DestroyButton.Position = UDim2.new(1, -30, 0, 0)
DestroyButton.Text = "X"
DestroyButton.Font = Enum.Font.SourceSansBold
DestroyButton.TextColor3 = Color3.fromRGB(255, 255, 255)
DestroyButton.TextSize = 20
DestroyButton.BackgroundColor3 = Color3.fromRGB(150, 50, 50)
DestroyButton.BorderColor3 = Color3.fromRGB(20, 20, 20)
DestroyButton.BorderSizePixel = 1
DestroyButton.Parent = HeaderFrame
DestroyButton.ZIndex = 2
DestroyButton.MouseButton1Click:Connect(function()
MainMusicPlayerGUI:Destroy()
if _G.currentSound then
stopSound()
end
print("Music Player GUI closed.")
end)
local ContentContainer = Instance.new("Frame")
ContentContainer.Size = UDim2.new(1, 0, 1, -30)
ContentContainer.Position = UDim2.new(0, 0, 0, 30)
ContentContainer.BackgroundTransparency = 1
ContentContainer.Parent = MainPanel
ContentContainer.Name = "ContentContainer"
local ScrollingFrame = Instance.new("ScrollingFrame")
ScrollingFrame.Size = UDim2.new(1, -10, 1, -50)
ScrollingFrame.Position = UDim2.new(0, 5, 0, 25)
ScrollingFrame.AnchorPoint = Vector2.new(0, 0)
ScrollingFrame.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
ScrollingFrame.BorderColor3 = Color3.fromRGB(20, 20, 20)
ScrollingFrame.BorderSizePixel = 1
ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
ScrollingFrame.VerticalScrollBarInset = Enum.ScrollBarInset.Always
ScrollingFrame.ScrollBarImageColor3 = Color3.fromRGB(100, 100, 100)
ScrollingFrame.ScrollBarThickness = 6
ScrollingFrame.Parent = ContentContainer
ScrollingFrame.Active = true
local ButtonsContainer = Instance.new("Frame")
ButtonsContainer.Size = UDim2.new(1, 0, 1, 0)
ButtonsContainer.BackgroundTransparency = 1
ButtonsContainer.Parent = ScrollingFrame
local ListLayout = Instance.new("UIListLayout")
ListLayout.FillDirection = Enum.FillDirection.Vertical
ListLayout.Padding = UDim.new(0, BUTTON_PADDING)
ListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
ListLayout.VerticalAlignment = Enum.VerticalAlignment.Top
ListLayout.Parent = ButtonsContainer
-- Function to update the scrolling frame's CanvasSize
local function updateCanvasSize(scrollingFrameRef, listLayoutRef)
task.wait(0.05) -- Small delay to allow UIListLayout to update AbsoluteContentSize
local totalContentHeight = listLayoutRef.AbsoluteContentSize.Y
local minCanvasHeight = scrollingFrameRef.AbsoluteSize.Y
if minCanvasHeight == 0 then minCanvasHeight = 1 end -- Prevent division by zero
if totalContentHeight < minCanvasHeight then
scrollingFrameRef.CanvasSize = UDim2.new(0, 0, 0, minCanvasHeight + 1) -- Add 1 to ensure scrollbar appears if content is exactly minCanvasHeight
else
scrollingFrameRef.CanvasSize = UDim2.new(0, 0, 0, totalContentHeight)
end
end
-- Connect to ChildAdded/Removed and layout property changes to update CanvasSize for Main Player
ButtonsContainer.ChildAdded:Connect(function() updateCanvasSize(ScrollingFrame, ListLayout) end)
ButtonsContainer.ChildRemoved:Connect(function() updateCanvasSize(ScrollingFrame, ListLayout) end)
ListLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function() updateCanvasSize(ScrollingFrame, ListLayout) end)
ScrollingFrame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function() updateCanvasSize(ScrollingFrame, ListLayout) end) -- Important for dynamic resizing
-- Helper function to create uniform buttons
local function createContentButton(text, clickFunction)
local button = Instance.new("TextButton")
button.Size = UDim2.new(1, -10, 0, BUTTON_HEIGHT)
button.Text = text
button.Font = Enum.Font.SourceSans
button.TextColor3 = Color3.fromRGB(255, 255, 255)
button.TextSize = 14
button.BackgroundColor3 = Color3.fromRGB(80, 80, 80)
button.BorderColor3 = Color3.fromRGB(40, 40, 40)
button.BorderSizePixel = 1
button.Parent = ButtonsContainer
button.ZIndex = 2
button.MouseButton1Click:Connect(clickFunction)
return button
end
-- Input fields for Asset ID and optional Song Name
local AssetIdInput = Instance.new("TextBox")
AssetIdInput.Size = UDim2.new(1, -10, 0, TEXTBOX_HEIGHT)
AssetIdInput.PlaceholderText = "Enter Asset ID"
AssetIdInput.Text = ""
AssetIdInput.Font = Enum.Font.SourceSans
AssetIdInput.TextColor3 = Color3.fromRGB(255, 255, 255)
AssetIdInput.TextSize = 14
AssetIdInput.BackgroundColor3 = Color3.fromRGB(90, 90, 90)
AssetIdInput.BorderColor3 = Color3.fromRGB(50, 50, 50)
AssetIdInput.BorderSizePixel = 1
AssetIdInput.Parent = ButtonsContainer
AssetIdInput.ClearTextOnFocus = true
AssetIdInput.ZIndex = 2
local SongNameInput = Instance.new("TextBox")
SongNameInput.Size = UDim2.new(1, -10, 0, TEXTBOX_HEIGHT)
SongNameInput.PlaceholderText = "Optional: Song Name for Playlist"
SongNameInput.Text = ""
SongNameInput.Font = Enum.Font.SourceSans
SongNameInput.TextColor3 = Color3.fromRGB(255, 255, 255)
SongNameInput.TextSize = 14
SongNameInput.BackgroundColor3 = Color3.fromRGB(90, 90, 90)
SongNameInput.BorderColor3 = Color3.fromRGB(50, 50, 50)
SongNameInput.BorderSizePixel = 1
SongNameInput.Parent = ButtonsContainer
AssetIdInput.ClearTextOnFocus = true
SongNameInput.ZIndex = 2
createContentButton("Play Music (by ID)", function()
local assetId = AssetIdInput.Text
if assetId and assetId ~= "" then
playSound("rbxassetid://" .. assetId, DEFAULT_VOLUME, false)
else
print("Please enter an Asset ID to play.")
end
end)
createContentButton("Stop Music", stopSound)
createContentButton("Add Custom Song to Playlist", function()
local assetId = AssetIdInput.Text
local songName = SongNameInput.Text
if assetId and assetId ~= "" then
handlePlaylistAdd(assetId, songName ~= "" and songName or nil)
AssetIdInput.Text = ""
SongNameInput.Text = ""
else
print("Please enter an Asset ID to add to playlist.")
end
end)
createContentButton("Play/Pause Playlist", function()
if #_G.playlist > 0 then
if _G.currentSound and _G.currentSound.IsPlaying and _G.playlistPlaying then
_G.currentSound:Pause()
_G.playlistPlaying = false
print("Playlist paused.")
elseif _G.currentSound and not _G.currentSound.IsPlaying and not _G.playlistPlaying then
_G.currentSound:Play()
_G.playlistPlaying = true
print("Playlist resumed.")
elseif not _G.currentSound and not _G.playlistPlaying then
_G.currentPlaylistIndex = 1
_G.playlistPlaying = true
local nextSong = _G.playlist[_G.currentPlaylistIndex]
if nextSong then
print("Starting playlist playback with: " .. (nextSong.name or nextSong.id:gsub("rbxassetid://", "")))
playSound(nextSong.id, DEFAULT_VOLUME, false)
else
print("Playlist is empty or not active. Start by playing a playlist or add songs.")
end
end
else
print("Playlist is empty. Add songs first.")
end
end)
createContentButton("Next Song", function()
if _G.playlistPlaying and #_G.playlist > 0 then
_G.currentPlaylistIndex = _G.currentPlaylistIndex + 1
if _G.currentPlaylistIndex > #_G.playlist then
_G.currentPlaylistIndex = (_G.loopAllPlaylist and 1) or 0
if _G.currentPlaylistIndex == 0 then
_G.playlistPlaying = false
stopSound()
print("Playlist finished!")
return
end
end
local nextSong = _G.playlist[_G.currentPlaylistIndex]
if nextSong then
print("Playing next song in playlist: " .. (nextSong.name or nextSong.id:gsub("rbxassetid://", "")))
playSound(nextSong.id, DEFAULT_VOLUME, false)
else
print("Playlist is empty or not active. Start by playing a playlist or add songs.")
end
else
print("Playlist is empty or not active. Start by playing a playlist or add songs.")
end
end)
createContentButton("Previous Song", function()
if _G.playlistPlaying and #_G.playlist > 0 then
_G.currentPlaylistIndex = _G.currentPlaylistIndex - 1
if _G.currentPlaylistIndex < 1 then
_G.currentPlaylistIndex = #_G.playlist -- Loop back to end if at start
if _G.currentPlaylistIndex == 0 then -- Handle empty playlist edge case
_G.playlistPlaying = false
stopSound()
print("Playlist is empty, cannot go to previous song.")
return
end
end
local prevSong = _G.playlist[_G.currentPlaylistIndex]
if prevSong then
print("Playing previous song in playlist: " .. (prevSong.name or prevSong.id:gsub("rbxassetid://", "")))
playSound(prevSong.id, DEFAULT_VOLUME, false)
else
print("Playlist is empty or not active. Cannot go to previous song.")
end
else
print("Playlist is empty or not active. Cannot go to previous song.")
end
end)
createContentButton("Toggle Loop Current Song", function()
_G.loopCurrentSong = not _G.loopCurrentSong
print("Loop Current Song: " .. tostring(_G.loopCurrentSong))
if _G.currentSound then
_G.currentSound.Looped = _G.loopCurrentSong
end
end)
createContentButton("Toggle Loop All Playlist", function()
_G.loopAllPlaylist = not _G.loopAllPlaylist
print("Loop All Playlist: " .. tostring(_G.loopAllPlaylist))
end)
createContentButton("Remove Song from Playlist", function()
local query = AssetIdInput.Text
local nameQuery = SongNameInput.Text
if query ~= "" then
handlePlaylistRemove(query)
elseif nameQuery ~= "" then
handlePlaylistRemove(nameQuery)
else
print("Please enter an Asset ID or Song Name in the top boxes to remove.")
end
AssetIdInput.Text = ""
SongNameInput.Text = ""
end)
createContentButton("Wipe Entire Playlist", function()
if AssetIdInput:IsFocused() or SongNameInput:IsFocused() then
print("Please unfocus the text boxes first, then click 'Wipe Entire Playlist' again to confirm.")
else
wipePlaylist()
end
end)
createContentButton("List Playlist", handlePlaylistList)
-- NEW: Volume Text Box and Set Volume Button
local VolumeInput = Instance.new("TextBox")
VolumeInput.Size = UDim2.new(1, -10, 0, TEXTBOX_HEIGHT)
VolumeInput.PlaceholderText = "Enter Volume (0-1, e.g., 0.5)"
VolumeInput.Text = tostring(DEFAULT_VOLUME)
VolumeInput.Font = Enum.Font.SourceSans
VolumeInput.TextColor3 = Color3.fromRGB(255, 255, 255)
VolumeInput.TextSize = 14
VolumeInput.BackgroundColor3 = Color3.fromRGB(90, 90, 90)
VolumeInput.BorderColor3 = Color3.fromRGB(50, 50, 50)
VolumeInput.BorderSizePixel = 1
VolumeInput.Parent = ButtonsContainer
VolumeInput.ClearTextOnFocus = true
VolumeInput.ZIndex = 2
createContentButton("Set Volume", function()
local volumeText = VolumeInput.Text
local newVolume = tonumber(volumeText)
if newVolume and newVolume >= 0 and newVolume <= 1 then
if _G.currentSound then
_G.currentSound.Volume = newVolume
print("Volume set to: " .. newVolume)
else
print("No sound currently playing to set volume for. Default volume is " .. DEFAULT_VOLUME .. ".")
end
else
print("Invalid volume. Please enter a number between 0 and 1.")
end
end)
--- Popular Songs UI ---
local PopularSongsGUI = Instance.new("ScreenGui")
PopularSongsGUI.Name = "PopularSongsGUI"
PopularSongsGUI.Parent = PlayerGui
PopularSongsGUI.Enabled = false -- Hidden by default
local PopularSongsPanel = Instance.new("Frame")
PopularSongsPanel.Size = UDim2.new(0, 400, 0, 450) -- Widened the panel
-- CHANGE THIS LINE:
PopularSongsPanel.Position = UDim2.new(0.5, -100, 0.4, 0) -- This moves the panel's TOP edge to 40% down the screen
-- If you want to move it further UP, decrease the '0.4' value.
-- For example, 0.35, 0.3, etc.
PopularSongsPanel.AnchorPoint = Vector2.new(0, 0) -- Top-left aligned for centering calculations
PopularSongsPanel.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
PopularSongsPanel.BorderColor3 = Color3.fromRGB(20, 20, 20)
PopularSongsPanel.BorderSizePixel = 2
PopularSongsPanel.Draggable = true
PopularSongsPanel.Parent = PopularSongsGUI
local PSHeaderFrame = Instance.new("Frame")
PSHeaderFrame.Size = UDim2.new(1, 0, 0, 30)
PSHeaderFrame.Position = UDim2.new(0, 0, 0, 0)
PSHeaderFrame.BackgroundColor3 = Color3.fromRGB(50, 50, 50)
PSHeaderFrame.BorderColor3 = Color3.fromRGB(20, 20, 20)
PSHeaderFrame.BorderSizePixel = 1
PSHeaderFrame.Parent = PopularSongsPanel
local PSHeaderLabel = Instance.new("TextLabel")
PSHeaderLabel.Size = UDim2.new(1, -30, 1, 0)
PSHeaderLabel.Position = UDim2.new(0, 0, 0, 0)
PSHeaderLabel.Text = "Popular Songs"
PSHeaderLabel.Font = Enum.Font.SourceSansBold
PSHeaderLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
PSHeaderLabel.TextSize = 18
PSHeaderLabel.BackgroundTransparency = 1
PSHeaderLabel.Parent = PSHeaderFrame
PSHeaderLabel.ZIndex = 2
local PSCloseButton = Instance.new("TextButton")
PSCloseButton.Size = UDim2.new(0, 30, 0, 30)
PSCloseButton.Position = UDim2.new(1, -30, 0, 0)
PSCloseButton.Text = "X"
PSCloseButton.Font = Enum.Font.SourceSansBold
PSCloseButton.TextColor3 = Color3.fromRGB(255, 255, 255)
PSCloseButton.TextSize = 20
PSCloseButton.BackgroundColor3 = Color3.fromRGB(150, 50, 50)
PSCloseButton.BorderColor3 = Color3.fromRGB(20, 20, 20)
PSCloseButton.BorderSizePixel = 1
PSCloseButton.Parent = PSHeaderFrame
PSCloseButton.ZIndex = 2
PSCloseButton.MouseButton1Click:Connect(function()
PopularSongsGUI.Enabled = false
end)
local PSSubHeaderLabel = Instance.new("TextLabel")
PSSubHeaderLabel.Size = UDim2.new(1, 0, 0, 20)
PSSubHeaderLabel.Position = UDim2.new(0, 0, 0, 30)
PSSubHeaderLabel.Text = "Due to Roblox API limitations, this list is static. Special thanks to @spatxz on Blue App for fixing a comma i didnt see"
PSSubHeaderLabel.Font = Enum.Font.SourceSans
PSSubHeaderLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
PSSubHeaderLabel.TextSize = 12
PSSubHeaderLabel.BackgroundTransparency = 1
PSSubHeaderLabel.Parent = PopularSongsPanel
PSSubHeaderLabel.ZIndex = 2
local PSScollingFrame = Instance.new("ScrollingFrame")
PSScollingFrame.Size = UDim2.new(1, -10, 1, -60) -- Adjusted for header and sub-header
PSScollingFrame.Position = UDim2.new(0, 5, 0, 55)
PSScollingFrame.AnchorPoint = Vector2.new(0, 0)
PSScollingFrame.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
PSScollingFrame.BorderColor3 = Color3.fromRGB(20, 20, 20)
PSScollingFrame.BorderSizePixel = 1
PSScollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
PSScollingFrame.VerticalScrollBarInset = Enum.ScrollBarInset.Always
PSScollingFrame.ScrollBarImageColor3 = Color3.fromRGB(100, 100, 100)
PSScollingFrame.ScrollBarThickness = 6
PSScollingFrame.Parent = PopularSongsPanel
PSScollingFrame.Active = true
local PSButtonsContainer = Instance.new("Frame")
PSButtonsContainer.Size = UDim2.new(1, 0, 1, 0)
PSButtonsContainer.BackgroundTransparency = 1
PSButtonsContainer.Parent = PSScollingFrame
local PSListLayout = Instance.new("UIListLayout")
PSListLayout.FillDirection = Enum.FillDirection.Vertical
PSListLayout.Padding = UDim.new(0, BUTTON_PADDING)
PSListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
PSListLayout.VerticalAlignment = Enum.VerticalAlignment.Top
PSListLayout.Parent = PSButtonsContainer
-- Connect to ChildAdded/Removed and layout property changes to update CanvasSize for Popular Songs UI
PSButtonsContainer.ChildAdded:Connect(function() updateCanvasSize(PSScollingFrame, PSListLayout) end)
PSButtonsContainer.ChildRemoved:Connect(function() updateCanvasSize(PSScollingFrame, PSListLayout) end)
PSListLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function() updateCanvasSize(PSScollingFrame, PSListLayout) end)
PSScollingFrame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function() updateCanvasSize(PSScollingFrame, PSListLayout) end)
-- FIX: Re-position PopularSongsPanel higher on screen
-- PopularSongsPanel.Position = UDim2.new(0.5, -200, 0.5, -200) -- Original, center
PopularSongsPanel.Position = UDim2.new(0.5, -200, 0.2, 0) -- Adjusted to 20% down from the top
local function populatePopularSongsUI()
-- Clear existing buttons
for _, child in ipairs(PSButtonsContainer:GetChildren()) do
if child:IsA("Frame") then -- Check for the song entry frames
child:Destroy()
end
end
print("--- Loading Popular Songs ---")
_G.filteredPopularSongs = {}
local availableSongs = {}
for _, id in ipairs(POPULAR_SONGS_IDS) do
local isAvailable, name, defaultName = getAssetInfo(id)
if isAvailable then
table.insert(availableSongs, {id = id, name = name})
else
warn("Skipping unavailable popular song ID: " .. id .. " (Name: " .. defaultName .. ")")
end
task.wait(0.01) -- Yield to prevent script timeout on large lists
end
table.sort(availableSongs, function(a, b)
return a.name < b.name
end)
if #availableSongs == 0 then
local noSongsLabel = Instance.new("TextLabel")
noSongsLabel.Size = UDim2.new(1, -10, 0, 40)
noSongsLabel.Text = "No popular songs are currently available."
noSongsLabel.Font = Enum.Font.SourceSans
noSongsLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
noSongsLabel.TextSize = 14
noSongsLabel.BackgroundTransparency = 1
noSongsLabel.Parent = PSButtonsContainer
else
for i, song in ipairs(availableSongs) do
local songEntryFrame = Instance.new("Frame")
-- We now need enough height for the name (0.5) and the buttons (0.5) plus some padding
songEntryFrame.Size = UDim2.new(1, -10, 0, BUTTON_HEIGHT * 2.5) -- Increased total height for song entry
songEntryFrame.BackgroundTransparency = 1
songEntryFrame.Parent = PSButtonsContainer
local songNameLabel = Instance.new("TextLabel")
songNameLabel.Size = UDim2.new(1, 0, 0.4, 0) -- Give name 40% of vertical space
songNameLabel.Position = UDim2.new(0, 0, 0, 0)
songNameLabel.Text = song.name
songNameLabel.Font = Enum.Font.SourceSansBold
songNameLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
songNameLabel.TextSize = 14
songNameLabel.TextXAlignment = Enum.TextXAlignment.Left
songNameLabel.BackgroundTransparency = 1
songNameLabel.Parent = songEntryFrame
-- Container for buttons to properly use UIGridLayout below the name
local buttonsContainerInner = Instance.new("Frame")
buttonsContainerInner.Size = UDim2.new(1, 0, 0.6, 0) -- Take remaining 60% of vertical space
buttonsContainerInner.Position = UDim2.new(0, 0, 0.4, 0) -- Position below the song name label
buttonsContainerInner.BackgroundTransparency = 1
buttonsContainerInner.Parent = songEntryFrame
local buttonsLayout = Instance.new("UIGridLayout")
buttonsLayout.CellSize = UDim2.new(0.32, 0, 0.9, 0) -- Adjusted CellSize for better fit (slightly less than 1/3 width each)
buttonsLayout.CellPadding = UDim2.new(0, 2, 0, 0) -- Small horizontal padding
buttonsLayout.FillDirection = Enum.FillDirection.Horizontal
buttonsLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
buttonsLayout.StartCorner = Enum.StartCorner.TopLeft
buttonsLayout.SortOrder = Enum.SortOrder.LayoutOrder
buttonsLayout.Parent = buttonsContainerInner -- Parent to the new inner container
-- Buttons now fill their parent (buttonsContainerInner) and are laid out by UIGridLayout
local copyIDButton = Instance.new("TextButton")
copyIDButton.Size = UDim2.new(1, 0, 1, 0) -- Fill the cell size defined by UIGridLayout
copyIDButton.LayoutOrder = 1
copyIDButton.Text = "Copy ID"
copyIDButton.Font = Enum.Font.SourceSans
copyIDButton.TextColor3 = Color3.fromRGB(255, 255, 255)
copyIDButton.TextSize = 12
copyIDButton.BackgroundColor3 = Color3.fromRGB(70, 70, 70)
copyIDButton.BorderColor3 = Color3.fromRGB(30, 30, 30)
copyIDButton.BorderSizePixel = 1
copyIDButton.Parent = buttonsContainerInner
copyIDButton.MouseButton1Click:Connect(function()
UserInputService:SetClipboard(song.id)
print("Copied ID: " .. song.id)
end)
local playButton = Instance.new("TextButton")
playButton.Size = UDim2.new(1, 0, 1, 0) -- Fill the cell size
playButton.LayoutOrder = 2
playButton.Text = "Play"
playButton.Font = Enum.Font.SourceSans
playButton.TextColor3 = Color3.fromRGB(255, 255, 255)
playButton.TextSize = 12
playButton.BackgroundColor3 = Color3.fromRGB(60, 120, 60)
playButton.BorderColor3 = Color3.fromRGB(30, 60, 30)
playButton.BorderSizePixel = 1
playButton.Parent = buttonsContainerInner
playButton.MouseButton1Click:Connect(function()
playSound("rbxassetid://" .. song.id, DEFAULT_VOLUME, false)
end)
local addToPlaylistButton = Instance.new("TextButton")
addToPlaylistButton.Size = UDim2.new(1, 0, 1, 0) -- Fill the cell size
addToPlaylistButton.LayoutOrder = 3
addToPlaylistButton.Text = "Add to Playlist"
addToPlaylistButton.Font = Enum.Font.SourceSans
addToPlaylistButton.TextColor3 = Color3.fromRGB(255, 255, 255)
addToPlaylistButton.TextSize = 12
addToPlaylistButton.BackgroundColor3 = Color3.fromRGB(60, 60, 120)
addToPlaylistButton.BorderColor3 = Color3.fromRGB(30, 30, 60)
addToPlaylistButton.BorderSizePixel = 1
addToPlaylistButton.Parent = buttonsContainerInner
addToPlaylistButton.MouseButton1Click:Connect(function()
handlePlaylistAdd(song.id, song.name)
end)
end
end
updateCanvasSize(PSScollingFrame, PSListLayout) -- Update canvas size after populating
print("--- Popular Songs Loaded ---")
end
-- NEW: Button to show the Popular Songs UI
createContentButton("Show Popular Songs", function()
PopularSongsGUI.Enabled = not PopularSongsGUI.Enabled
if PopularSongsGUI.Enabled then
populatePopularSongsUI()
end
end)
-- Initial welcome message for console
print("Music Player loaded! Drag the UI around your screen. Use the F9 console for playlist details.")



havent tried it but its probably good
Você poderia adicionar uma forma de poder pesquisar as músicas do catálogo direto pelo script?
Hey @pinkblowbephia, i will try to! Thanks for the suggestion
@pinkblownephia sadly this doesnt seem to be possible, sorry!
Hello everyone, im currently finding a few more music ids, but most of them are sadly down. Stay tuned! Also, i‘ll try to fix following issues: You cant drag the UI on mobile, The UI disappears when using „reset character“ (profanity filter), leaving the song playing too. Happy listening everyone! Update: yeaahhh you apparently cant fix those easily, i‘ll focus on adding more songs. Sorry!
FE?
serversided?