local QBCore = exports[Config.Core]:GetCoreObject() local PlayerData, Targets, Props = {}, {}, {} local Locations = {} local function removeTargets() for k in pairs(Targets) do exports['qb-target']:RemoveZone(k) end Targets = {} for i = 1, #Props do DeleteEntity(Props[i]) end Props = {} end local function makeTargets() removeTargets() for i = 1, #Locations do if Locations[i].enableBooth then local RequireJob, RequireGang = nil, nil if Locations[i].job then RequireJob = Locations[i].job if RequireJob == "public" then RequireJob = nil end end if Locations[i].gang then RequireGang = Locations[i].RequireGang end Targets["Booth"..i] = exports['qb-target']:AddCircleZone("Booth"..i, Locations[i].coords, 0.6, {name="Booth"..i, debugPoly=Config.Debug, useZ=true, }, { options = { { event = "jim-djbooth:client:playMusic", icon = "fab fa-youtube", label = Loc[Config.Lan].target["dj_booth"], job = RequireJob, gang = RequireGang, zoneNum = i, coords = Locations[i].coords }, }, distance = 2.0 }) if Locations[i].prop then Props[#Props+1] = makeProp({prop = Locations[i].prop, coords = vec4(Locations[i].coords.x, Locations[i].coords.y, Locations[i].coords.z, math.random(1,359)+0.0) }, true, false) end end end end local function syncLocations() local p = promise.new() QBCore.Functions.TriggerCallback('jim-djbooth:server:syncLocations', function(cb) p:resolve(cb) end) Locations = Citizen.Await(p) makeTargets() end AddEventHandler('onResourceStart', function(r) if (GetCurrentResourceName() ~= r) then return end if GetResourceState("xsound") ~= "started" then print("xSound not started, script won't function") end PlayerData = QBCore.Functions.GetPlayerData() Wait(5000) syncLocations() end) AddEventHandler('QBCore:Client:OnPlayerLoaded', function() PlayerData = QBCore.Functions.GetPlayerData() Wait(5000) syncLocations() end) RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo) PlayerData.job = JobInfo end) RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() PlayerData = {} end) RegisterNetEvent("jim-djbooth:client:syncLocations", function(newLocations) Locations = newLocations makeTargets() end) RegisterNetEvent("jim-djbooth:client:playMusic", function(data) local booth = "" for k, v in pairs(Locations) do if #(GetEntityCoords(PlayerPedId()) - v["coords"]) <= v["radius"] then if v["job"] then booth = v["job"]..k elseif v["gang"] then booth = v["gang"]..k end end end local song = { playing = "", duration = "", timeStamp = "", duration = "", url = "", icon = "", header = Loc[Config.Lan].menu["no_song"], txt = "", volume = "" } local p = promise.new() QBCore.Functions.TriggerCallback('jim-djbooth:songInfo', function(cb) p:resolve(cb) end) previousSongs = Citizen.Await(p) -- Grab song info and build table if exports["xsound"]:soundExists(booth) then song = { playing = exports["xsound"]:isPlaying(booth), timeStamp = "", url = exports["xsound"]:getLink(booth), icon = "https://img.youtube.com/vi/"..string.sub(exports["xsound"]:getLink(booth), - 11).."/mqdefault.jpg", header = "", txt = exports["xsound"]:getLink(booth), volume = math.ceil(exports["xsound"]:getVolume(booth)*100) } if exports["xsound"]:isPlaying(booth) then song.header = Loc[Config.Lan].menu["cur_playing"] end if exports["xsound"]:isPaused(booth) then song.header = Loc[Config.Lan].menu["cur_paused"] end if exports["xsound"]:getMaxDuration(booth) == 0 then song.timeStamp = Loc[Config.Lan].menu["live"] end if exports["xsound"]:getMaxDuration(booth) > 0 then local timestamp = (exports["xsound"]:getTimeStamp(booth) * 10) local mm = (timestamp // (60 * 10)) % 60. local ss = (timestamp // 10) % 60. timestamp = string.format("%02d:%02d", mm, ss) local duration = (exports["xsound"]:getMaxDuration(booth) * 10) mm = (duration // (60 * 10)) % 60. ss = (duration // 10) % 60. duration = string.format("%02d:%02d", mm, ss) song.timeStamp = "("..timestamp.."/"..duration..")" if exports["xsound"]:isPlaying(booth) then song.timeStamp = "🔊 "..song.timeStamp else song.timeStamp = "🔇 "..song.timeStamp end end end local musicMenu = {} if Config.Menu == "qb" then musicMenu[#musicMenu+1] = { isMenuHeader = true, header = '  '..Loc[Config.Lan].target["dj_booth"], txt = "" } musicMenu[#musicMenu+1] = { icon = "fas fa-circle-xmark", header = "", txt = Loc[Config.Lan].menu["close"], params = { event = "qb-menu:client:closemenu" } } end musicMenu[#musicMenu + 1] = { canClick = false, disabled = true, image = song.icon, icon = song.icon, header = song.header, txt = song.txt.."
"..song.timeStamp, --qb-menu title = song.header, description = song.txt.."\n"..song.timeStamp, -- ox_lib } musicMenu[#musicMenu+1] = { icon = "fab fa-youtube", header = song.header, txt = Loc[Config.Lan].menu["enter_url"], --qb-menu title = Loc[Config.Lan].menu["play"], -- ox_lib header = Loc[Config.Lan].menu["play"], event = "jim-djbooth:client:musicMenu", args = { zoneNum = data.zoneNum }, -- ox_lib params = { event = "jim-djbooth:client:musicMenu", args = { zoneNum = data.zoneNum } } } if previousSongs[booth] then musicMenu[#musicMenu+1] = { icon = "fas fa-clock-rotate-left", header = Loc[Config.Lan].menu["history"], title = Loc[Config.Lan].menu["history"], -- ox_lib event = "jim-djbooth:client:history", args = { history = previousSongs[booth], zoneNum = data.zoneNum }, -- ox_lib params = { event = "jim-djbooth:client:history", args = { history = previousSongs[booth], zoneNum = data.zoneNum } } } end if exports["xsound"]:soundExists(booth) then if exports["xsound"]:isPlaying(booth) then musicMenu[#musicMenu+1] = { icon = "fas fa-pause", header = Loc[Config.Lan].menu["text_pause"], title = Loc[Config.Lan].menu["text_pause"], serverEvent = "jim-djbooth:server:PauseResume", args = { zoneNum = data.zoneNum }, params = { isServer = true, event = "jim-djbooth:server:PauseResume", args = { zoneNum = data.zoneNum } } } elseif exports["xsound"]:isPaused(booth) then musicMenu[#musicMenu+1] = { icon = "fas fa-play", header = Loc[Config.Lan].menu["text_resume"], title = Loc[Config.Lan].menu["text_resume"], serverEvent = "jim-djbooth:server:PauseResume", args = { zoneNum = data.zoneNum }, params = { isServer = true, event = "jim-djbooth:server:PauseResume", args = { zoneNum = data.zoneNum } } } end musicMenu[#musicMenu+1] = { icon = "fas fa-volume-off", header = Loc[Config.Lan].menu["volume"]..song.volume.."%", title = Loc[Config.Lan].menu["volume"]..song.volume.."%", progress = tonumber(song.volume), event = "jim-djbooth:client:changeVolume", args = { zoneNum = data.zoneNum, }, params = { event = "jim-djbooth:client:changeVolume", args = { zoneNum = data.zoneNum } } } musicMenu[#musicMenu+1] = { icon = "fas fa-stop", header = Loc[Config.Lan].menu["stop"], title = Loc[Config.Lan].menu["stop"], serverEvent = "jim-djbooth:server:stopMusic", args = { zoneNum = data.zoneNum }, -- ox_lib params = { isServer = true, event = "jim-djbooth:server:stopMusic", args = { zoneNum = data.zoneNum } } } end if Config.Menu == "ox" then exports.ox_lib:registerContext({id = 'booth', title = Loc[Config.Lan].target["dj_booth"], position = 'top-right', options = musicMenu }) exports.ox_lib:showContext("booth") elseif Config.Menu == "qb" then exports['qb-menu']:openMenu(musicMenu) end song = nil end) RegisterNetEvent("jim-djbooth:client:history", function(data) local musicMenu = {} if Config.Menu == "qb" then musicMenu[#musicMenu+1] = { icon = "fas fa-clock-rotate-left", isMenuHeader = true, header = "  "..Loc[Config.Lan].target["dj_booth"], txt = Loc[Config.Lan].menu["history_play"] } end musicMenu[#musicMenu+1] = { icon = "fas fa-circle-arrow-left", header = "", txt = Loc[Config.Lan].menu["back"], title = Loc[Config.Lan].menu["back"], event = "jim-djbooth:client:playMusic", args = { job = data.job, zone = data.zoneNum }, params = { event = "jim-djbooth:client:playMusic", args = { job = data.job, zone = data.zoneNum } } } for i = #data.history, 1, -1 do musicMenu[#musicMenu+1] = { image = "https://img.youtube.com/vi/"..string.sub(data.history[i], - 11).."/mqdefault.jpg", icon = "https://img.youtube.com/vi/"..string.sub(data.history[i], - 11).."/mqdefault.jpg", header = "", txt = data.history[i], title = data.history[i], event = "jim-djbooth:client:historyPlay", args = { song = data.history[i], zoneNum = data.zoneNum }, params = { event = "jim-djbooth:client:historyPlay", args = { song = data.history[i], zoneNum = data.zoneNum } } } end if Config.Menu == "ox" then exports.ox_lib:registerContext({ id = 'history', title = Loc[Config.Lan].target["dj_booth"], position = 'top-right', options = musicMenu,}) exports.ox_lib:showContext("history") elseif Config.Menu == "qb" then exports['qb-menu']:openMenu(musicMenu) end end) RegisterNetEvent('jim-djbooth:client:historyPlay', function(data) TriggerServerEvent('jim-djbooth:server:playMusic', data.song, data.zoneNum) end) RegisterNetEvent('jim-djbooth:client:musicMenu', function(data) local dialog = nil if Config.Menu == "ox" then dialog = exports.ox_lib:inputDialog(Loc[Config.Lan].menu["select"], {Loc[Config.Lan].menu["youtube_url"]}) elseif Config.Menu == "qb" then dialog = exports['qb-input']:ShowInput({ header = Loc[Config.Lan].menu["select"], submitText = Loc[Config.Lan].menu["submit"], inputs = { { type = 'text', isRequired = true, name = 'song', text = Loc[Config.Lan].menu["youtube_url"] } } }) end if dialog then if not dialog.song and not dialog[1] then return end -- Attempt to correct link if missing "youtube" as some scripts use just the video id at the end if not string.find((dialog.song or dialog[1]), "youtu") then dialog.song = "https://www.youtube.com/watch?v="..(dialog.song or dialog[1]) end triggerNotify(nil, Loc[Config.Lan].notify["load_link"]..(dialog.song or dialog[1])) TriggerServerEvent('jim-djbooth:server:playMusic', (dialog.song or dialog[1]), data.zoneNum) end end) RegisterNetEvent('jim-djbooth:client:changeVolume', function(data) local dialog = nil if Config.Menu == "ox" then dialog = exports.ox_lib:inputDialog(Loc[Config.Lan].menu["music_volume"], {Loc[Config.Lan].menu["range"]}) elseif Config.Menu == "qb" then dialog = exports['qb-input']:ShowInput({ header = Loc[Config.Lan].menu["music_volume"], submitText = Loc[Config.Lan].menu["submit"], inputs = { { type = 'text', isRequired = true, name = 'volume', text = Loc[Config.Lan].menu["range"] } } }) end if dialog then if not dialog.volume and not dialog[1] then return end -- Automatically correct from numbers to be numbers xsound understands dialog.volume = ((dialog.volume or dialog[1]) / 100) -- Don't let numbers go too high or too low if dialog.volume <= 0.01 then dialog.volume = 0.01 end if dialog.volume > 1.0 then dialog.volume = 1.0 end triggerNotify(nil, Loc[Config.Lan].notify["new_volume"]..math.ceil(dialog.volume * 100).."%", "success") TriggerServerEvent('jim-djbooth:server:changeVolume', dialog.volume, data.zoneNum) end end) AddEventHandler('onResourceStop', function(r) if r ~= GetCurrentResourceName() then return end if GetResourceState("qb-target") == "started" or GetResourceState("ox_target") == "started" then for k in pairs(Targets) do exports['qb-target']:RemoveZone(k) end for i = 1, #Props do DeleteEntity(Props[i]) end end end)