575 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			575 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
local QBCore = exports['qb-core']:GetCoreObject()
 | 
						|
 | 
						|
-- Aktive DJ-Booths
 | 
						|
local activeDJBooths = {}
 | 
						|
 | 
						|
-- Database Setup
 | 
						|
CreateThread(function()
 | 
						|
    MySQL.query([[
 | 
						|
        CREATE TABLE IF NOT EXISTS dj_playlists (
 | 
						|
            id INT AUTO_INCREMENT PRIMARY KEY,
 | 
						|
            name VARCHAR(255) NOT NULL,
 | 
						|
            owner VARCHAR(50) NOT NULL,
 | 
						|
            description TEXT DEFAULT NULL,
 | 
						|
            is_public TINYINT(1) DEFAULT 0,
 | 
						|
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
						|
            updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
 | 
						|
        )
 | 
						|
    ]])
 | 
						|
    
 | 
						|
    MySQL.query([[
 | 
						|
        CREATE TABLE IF NOT EXISTS dj_playlist_songs (
 | 
						|
            id INT AUTO_INCREMENT PRIMARY KEY,
 | 
						|
            playlist_id INT NOT NULL,
 | 
						|
            title VARCHAR(255) NOT NULL,
 | 
						|
            artist VARCHAR(255) DEFAULT NULL,
 | 
						|
            url TEXT NOT NULL,
 | 
						|
            converted_url TEXT DEFAULT NULL,
 | 
						|
            duration INT DEFAULT NULL,
 | 
						|
            position INT DEFAULT 0,
 | 
						|
            song_type VARCHAR(20) DEFAULT 'direct',
 | 
						|
            thumbnail TEXT DEFAULT NULL,
 | 
						|
            added_by VARCHAR(50) DEFAULT NULL,
 | 
						|
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
						|
            FOREIGN KEY (playlist_id) REFERENCES dj_playlists(id) ON DELETE CASCADE
 | 
						|
        )
 | 
						|
    ]])
 | 
						|
    
 | 
						|
    MySQL.query([[
 | 
						|
        CREATE TABLE IF NOT EXISTS dj_url_cache (
 | 
						|
            id INT AUTO_INCREMENT PRIMARY KEY,
 | 
						|
            original_url VARCHAR(500) NOT NULL,
 | 
						|
            converted_url TEXT NOT NULL,
 | 
						|
            video_id VARCHAR(50) DEFAULT NULL,
 | 
						|
            title VARCHAR(255) DEFAULT NULL,
 | 
						|
            duration INT DEFAULT NULL,
 | 
						|
            thumbnail TEXT DEFAULT NULL,
 | 
						|
            expires_at TIMESTAMP NOT NULL,
 | 
						|
            hit_count INT DEFAULT 1,
 | 
						|
            created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
						|
            last_accessed TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
 | 
						|
            UNIQUE KEY (original_url(255))
 | 
						|
        )
 | 
						|
    ]])
 | 
						|
    
 | 
						|
    MySQL.query([[
 | 
						|
        CREATE TABLE IF NOT EXISTS dj_session_history (
 | 
						|
            id INT AUTO_INCREMENT PRIMARY KEY,
 | 
						|
            dj_citizenid VARCHAR(50) NOT NULL,
 | 
						|
            dj_name VARCHAR(100) NOT NULL,
 | 
						|
            booth_name VARCHAR(100) NOT NULL,
 | 
						|
            song_title VARCHAR(255) NOT NULL,
 | 
						|
            song_url TEXT NOT NULL,
 | 
						|
            song_type VARCHAR(20) DEFAULT 'direct',
 | 
						|
            volume INT DEFAULT 50,
 | 
						|
            duration_played INT DEFAULT NULL,
 | 
						|
            session_start TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
 | 
						|
            session_end TIMESTAMP NULL DEFAULT NULL,
 | 
						|
            listeners_count INT DEFAULT 0
 | 
						|
        )
 | 
						|
    ]])
 | 
						|
end)
 | 
						|
 | 
						|
-- YouTube URL Funktionen
 | 
						|
local function extractYouTubeVideoId(url)
 | 
						|
    -- YouTube URL Patterns
 | 
						|
    local patterns = {
 | 
						|
        "youtube%.com/watch%?v=([%w%-_]+)",
 | 
						|
        "youtube%.com/watch%?.*&v=([%w%-_]+)",
 | 
						|
        "youtu%.be/([%w%-_]+)",
 | 
						|
        "youtube%.com/embed/([%w%-_]+)"
 | 
						|
    }
 | 
						|
    
 | 
						|
    for _, pattern in ipairs(patterns) do
 | 
						|
        local videoId = string.match(url, pattern)
 | 
						|
        if videoId then
 | 
						|
            return videoId
 | 
						|
        end
 | 
						|
    end
 | 
						|
    
 | 
						|
    return nil
 | 
						|
end
 | 
						|
 | 
						|
local function cleanYouTubeUrl(url)
 | 
						|
    local videoId = extractYouTubeVideoId(url)
 | 
						|
    if not videoId then
 | 
						|
        return nil
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Erstelle saubere YouTube URL ohne Playlist-Parameter
 | 
						|
    return "https://www.youtube.com/watch?v=" .. videoId
 | 
						|
end
 | 
						|
 | 
						|
-- Events
 | 
						|
RegisterServerEvent('dj:server:playMusic')
 | 
						|
AddEventHandler('dj:server:playMusic', function(data)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    -- Speichere den aktuellen DJ-Status
 | 
						|
    activeDJBooths[data.booth.name] = {
 | 
						|
        url = data.url,
 | 
						|
        title = data.title,
 | 
						|
        volume = data.volume,
 | 
						|
        range = data.range,
 | 
						|
        dj = {
 | 
						|
            id = Player.PlayerData.citizenid,
 | 
						|
            name = Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname
 | 
						|
        },
 | 
						|
        coords = data.booth.coords
 | 
						|
    }
 | 
						|
    
 | 
						|
    -- Sende an alle Spieler
 | 
						|
    TriggerClientEvent('dj:client:playMusic', -1, data)
 | 
						|
    
 | 
						|
    -- Log für Admin
 | 
						|
    print(('[DJ System] %s spielt Musik ab: %s | Booth: %s'):format(
 | 
						|
        GetPlayerName(src), 
 | 
						|
        data.title,
 | 
						|
        data.booth.name
 | 
						|
    ))
 | 
						|
    
 | 
						|
    -- Speichere in Datenbank
 | 
						|
    MySQL.insert('INSERT INTO dj_session_history (dj_citizenid, dj_name, booth_name, song_title, song_url, song_type, volume, session_start) VALUES (?, ?, ?, ?, ?, ?, ?, NOW())', {
 | 
						|
        Player.PlayerData.citizenid,
 | 
						|
        Player.PlayerData.charinfo.firstname .. ' ' .. Player.PlayerData.charinfo.lastname,
 | 
						|
        data.booth.name,
 | 
						|
        data.title,
 | 
						|
        data.url,
 | 
						|
        string.match(data.url, "youtube") and 'youtube' or 'direct',
 | 
						|
        data.volume
 | 
						|
    })
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:stopMusic')
 | 
						|
AddEventHandler('dj:server:stopMusic', function(boothName)
 | 
						|
    local src = source
 | 
						|
    
 | 
						|
    -- Entferne DJ-Status
 | 
						|
    if activeDJBooths[boothName] then
 | 
						|
        -- Aktualisiere Session-Ende in der Datenbank
 | 
						|
        local djData = activeDJBooths[boothName]
 | 
						|
        if djData and djData.dj then
 | 
						|
            MySQL.update('UPDATE dj_session_history SET session_end = NOW() WHERE dj_citizenid = ? AND booth_name = ? AND session_end IS NULL', {
 | 
						|
                djData.dj.id,
 | 
						|
                boothName
 | 
						|
            })
 | 
						|
        end
 | 
						|
        
 | 
						|
        activeDJBooths[boothName] = nil
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Sende an alle Spieler
 | 
						|
    TriggerClientEvent('dj:client:stopMusic', -1, boothName)
 | 
						|
    
 | 
						|
    print(('[DJ System] %s hat die Musik gestoppt in: %s'):format(GetPlayerName(src), boothName))
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:setVolume')
 | 
						|
AddEventHandler('dj:server:setVolume', function(data)
 | 
						|
    local src = source
 | 
						|
    
 | 
						|
    -- Aktualisiere DJ-Status
 | 
						|
    if activeDJBooths[data.booth.name] then
 | 
						|
        activeDJBooths[data.booth.name].volume = data.volume
 | 
						|
        activeDJBooths[data.booth.name].range = data.range
 | 
						|
    end
 | 
						|
    
 | 
						|
    -- Sende an alle Spieler
 | 
						|
    TriggerClientEvent('dj:client:setVolume', -1, data)
 | 
						|
    
 | 
						|
    print(('[DJ System] %s hat die Lautstärke auf %d%% gesetzt in: %s'):format(
 | 
						|
        GetPlayerName(src), 
 | 
						|
        data.volume,
 | 
						|
        data.booth.name
 | 
						|
    ))
 | 
						|
end)
 | 
						|
 | 
						|
-- Playlist Management
 | 
						|
RegisterServerEvent('dj:server:getPlaylists')
 | 
						|
AddEventHandler('dj:server:getPlaylists', function()
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    MySQL.query('SELECT * FROM dj_playlists WHERE owner = ? OR is_public = 1', {Player.PlayerData.citizenid}, function(playlists)
 | 
						|
        local playlistData = {}
 | 
						|
        
 | 
						|
        for _, playlist in pairs(playlists) do
 | 
						|
            MySQL.query('SELECT * FROM dj_playlist_songs WHERE playlist_id = ? ORDER BY position', {playlist.id}, function(songs)
 | 
						|
                table.insert(playlistData, {
 | 
						|
                    id = playlist.id,
 | 
						|
                    name = playlist.name,
 | 
						|
                    description = playlist.description,
 | 
						|
                    isPublic = playlist.is_public == 1,
 | 
						|
                    isOwner = playlist.owner == Player.PlayerData.citizenid,
 | 
						|
                    songs = songs
 | 
						|
                })
 | 
						|
                
 | 
						|
                if #playlistData == #playlists then
 | 
						|
                    TriggerClientEvent('dj:client:updatePlaylists', src, playlistData)
 | 
						|
                end
 | 
						|
            end)
 | 
						|
        end
 | 
						|
        
 | 
						|
        if #playlists == 0 then
 | 
						|
            TriggerClientEvent('dj:client:updatePlaylists', src, {})
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:createPlaylist')
 | 
						|
AddEventHandler('dj:server:createPlaylist', function(name, description, isPublic)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    MySQL.insert('INSERT INTO dj_playlists (name, owner, description, is_public) VALUES (?, ?, ?, ?)', {
 | 
						|
        name,
 | 
						|
        Player.PlayerData.citizenid,
 | 
						|
        description or '',
 | 
						|
        isPublic and 1 or 0
 | 
						|
    }, function(id)
 | 
						|
        if id then
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Playlist "' .. name .. '" wurde erstellt!', 'success')
 | 
						|
            TriggerEvent('dj:server:getPlaylists', src)
 | 
						|
        else
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Erstellen der Playlist!', 'error')
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:addSongToPlaylist')
 | 
						|
AddEventHandler('dj:server:addSongToPlaylist', function(playlistId, song)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    -- Prüfe ob Playlist dem Spieler gehört
 | 
						|
    MySQL.query('SELECT * FROM dj_playlists WHERE id = ? AND (owner = ? OR is_public = 1)', {
 | 
						|
        playlistId,
 | 
						|
        Player.PlayerData.citizenid
 | 
						|
    }, function(result)
 | 
						|
        if result[1] then
 | 
						|
            -- Bereinige YouTube URL
 | 
						|
            local songUrl = song.url
 | 
						|
            if string.match(songUrl, "youtube") then
 | 
						|
                local cleanUrl = cleanYouTubeUrl(songUrl)
 | 
						|
                if cleanUrl then
 | 
						|
                    songUrl = cleanUrl
 | 
						|
                end
 | 
						|
            end
 | 
						|
            
 | 
						|
            -- Hole höchste Position
 | 
						|
            MySQL.query('SELECT MAX(position) as max_pos FROM dj_playlist_songs WHERE playlist_id = ?', {playlistId}, function(posResult)
 | 
						|
                local position = 1
 | 
						|
                if posResult[1] and posResult[1].max_pos then
 | 
						|
                    position = posResult[1].max_pos + 1
 | 
						|
                end
 | 
						|
                
 | 
						|
                -- Füge Song hinzu
 | 
						|
                MySQL.insert('INSERT INTO dj_playlist_songs (playlist_id, title, artist, url, song_type, position, added_by) VALUES (?, ?, ?, ?, ?, ?, ?)', {
 | 
						|
                    playlistId,
 | 
						|
                    song.title,
 | 
						|
                    song.artist or '',
 | 
						|
                    songUrl,
 | 
						|
                    string.match(songUrl, "youtube") and 'youtube' or 'direct',
 | 
						|
                    position,
 | 
						|
                    Player.PlayerData.citizenid
 | 
						|
                }, function(id)
 | 
						|
                    if id then
 | 
						|
                        TriggerClientEvent('QBCore:Notify', src, 'Song wurde zur Playlist hinzugefügt!', 'success')
 | 
						|
                        TriggerEvent('dj:server:getPlaylists', src)
 | 
						|
                    else
 | 
						|
                        TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Hinzufügen des Songs!', 'error')
 | 
						|
                    end
 | 
						|
                end)
 | 
						|
            end)
 | 
						|
        else
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung für diese Playlist!', 'error')
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:removeSongFromPlaylist')
 | 
						|
AddEventHandler('dj:server:removeSongFromPlaylist', function(playlistId, songId)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    -- Prüfe ob Playlist dem Spieler gehört
 | 
						|
    MySQL.query('SELECT * FROM dj_playlists WHERE id = ? AND owner = ?', {
 | 
						|
        playlistId,
 | 
						|
        Player.PlayerData.citizenid
 | 
						|
    }, function(result)
 | 
						|
        if result[1] then
 | 
						|
            MySQL.query('DELETE FROM dj_playlist_songs WHERE id = ? AND playlist_id = ?', {
 | 
						|
                songId,
 | 
						|
                playlistId
 | 
						|
            }, function(affectedRows)
 | 
						|
                if affectedRows > 0 then
 | 
						|
                    TriggerClientEvent('QBCore:Notify', src, 'Song wurde aus der Playlist entfernt!', 'success')
 | 
						|
                    TriggerEvent('dj:server:getPlaylists', src)
 | 
						|
                else
 | 
						|
                    TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Entfernen des Songs!', 'error')
 | 
						|
                end
 | 
						|
            end)
 | 
						|
        else
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Du hast keine Berechtigung für diese Playlist!', 'error')
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:deletePlaylist')
 | 
						|
AddEventHandler('dj:server:deletePlaylist', function(playlistId)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    MySQL.query('DELETE FROM dj_playlists WHERE id = ? AND owner = ?', {
 | 
						|
        playlistId,
 | 
						|
        Player.PlayerData.citizenid
 | 
						|
    }, function(affectedRows)
 | 
						|
        if affectedRows > 0 then
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Playlist wurde gelöscht!', 'success')
 | 
						|
            TriggerEvent('dj:server:getPlaylists', src)
 | 
						|
        else
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Löschen der Playlist!', 'error')
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
RegisterServerEvent('dj:server:updatePlaylist')
 | 
						|
AddEventHandler('dj:server:updatePlaylist', function(playlistId, name, description, isPublic)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    MySQL.update('UPDATE dj_playlists SET name = ?, description = ?, is_public = ? WHERE id = ? AND owner = ?', {
 | 
						|
        name,
 | 
						|
        description or '',
 | 
						|
        isPublic and 1 or 0,
 | 
						|
        playlistId,
 | 
						|
        Player.PlayerData.citizenid
 | 
						|
    }, function(affectedRows)
 | 
						|
        if affectedRows > 0 then
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Playlist wurde aktualisiert!', 'success')
 | 
						|
            TriggerEvent('dj:server:getPlaylists', src)
 | 
						|
        else
 | 
						|
            TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Aktualisieren der Playlist!', 'error')
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
-- Synchronisation
 | 
						|
RegisterServerEvent('dj:server:requestActiveDJs')
 | 
						|
AddEventHandler('dj:server:requestActiveDJs', function()
 | 
						|
    local src = source
 | 
						|
    TriggerClientEvent('dj:client:receiveActiveDJs', src, activeDJBooths)
 | 
						|
end)
 | 
						|
 | 
						|
-- Wenn ein Spieler das Spiel verlässt und DJ war, stoppe die Musik
 | 
						|
AddEventHandler('playerDropped', function(reason)
 | 
						|
    local src = source
 | 
						|
    local Player = QBCore.Functions.GetPlayer(src)
 | 
						|
    if not Player then return end
 | 
						|
    
 | 
						|
    -- Prüfe ob Spieler DJ war
 | 
						|
    for boothName, boothData in pairs(activeDJBooths) do
 | 
						|
        if boothData.dj and boothData.dj.id == Player.PlayerData.citizenid then
 | 
						|
            -- Spieler war DJ, stoppe Musik
 | 
						|
            
 | 
						|
            -- Aktualisiere Session-Ende in der Datenbank
 | 
						|
            MySQL.update('UPDATE dj_session_history SET session_end = NOW() WHERE dj_citizenid = ? AND booth_name = ? AND session_end IS NULL', {
 | 
						|
                boothData.dj.id,
 | 
						|
                boothName
 | 
						|
            })
 | 
						|
            
 | 
						|
            activeDJBooths[boothName] = nil
 | 
						|
            TriggerClientEvent('dj:client:stopMusic', -1, boothName)
 | 
						|
            
 | 
						|
            print(('[DJ System] DJ %s hat das Spiel verlassen, Musik in %s gestoppt'):format(
 | 
						|
                GetPlayerName(src),
 | 
						|
                boothName
 | 
						|
            ))
 | 
						|
        end
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Cache Cleanup (läuft alle 30 Minuten)
 | 
						|
CreateThread(function()
 | 
						|
    while true do
 | 
						|
        Wait(1800000) -- 30 Minuten
 | 
						|
        MySQL.query('DELETE FROM dj_url_cache WHERE expires_at < NOW()')
 | 
						|
        print('[DJ System] Cache bereinigt')
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Initialisiere Standard-Playlists
 | 
						|
CreateThread(function()
 | 
						|
    Wait(5000) -- Warte bis Datenbank bereit ist
 | 
						|
    
 | 
						|
    -- Prüfe ob Standard-Playlists existieren
 | 
						|
    MySQL.query('SELECT * FROM dj_playlists WHERE owner = ?', {'system'}, function(result)
 | 
						|
        if #result == 0 then
 | 
						|
            print('[DJ System] Erstelle Standard-Playlists')
 | 
						|
            
 | 
						|
            -- Erstelle Standard-Playlists
 | 
						|
            for _, playlist in pairs(Config.DefaultPlaylists) do
 | 
						|
                MySQL.insert('INSERT INTO dj_playlists (name, owner, description, is_public) VALUES (?, ?, ?, ?)', {
 | 
						|
                    playlist.name,
 | 
						|
                    'system',
 | 
						|
                    'Standard-Playlist',
 | 
						|
                    1
 | 
						|
                }, function(playlistId)
 | 
						|
                    if playlistId then
 | 
						|
                        -- Füge Songs hinzu
 | 
						|
                        for position, song in ipairs(playlist.songs) do
 | 
						|
                            MySQL.insert('INSERT INTO dj_playlist_songs (playlist_id, title, url, song_type, position, added_by) VALUES (?, ?, ?, ?, ?, ?)', {
 | 
						|
                                playlistId,
 | 
						|
                                song.title,
 | 
						|
                                song.url,
 | 
						|
                                string.match(song.url, "youtube") and 'youtube' or 'direct',
 | 
						|
                                position,
 | 
						|
                                'system'
 | 
						|
                            })
 | 
						|
                        end
 | 
						|
                        
 | 
						|
                        print('[DJ System] Standard-Playlist erstellt: ' .. playlist.name)
 | 
						|
                    end
 | 
						|
                end)
 | 
						|
            end
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
-- QBCore Callbacks
 | 
						|
QBCore.Functions.CreateCallback('dj:server:getActiveDJs', function(source, cb)
 | 
						|
    cb(activeDJBooths)
 | 
						|
end)
 | 
						|
 | 
						|
QBCore.Functions.CreateCallback('dj:server:getPlaylists', function(source, cb)
 | 
						|
    local Player = QBCore.Functions.GetPlayer(source)
 | 
						|
    if not Player then return cb({}) end
 | 
						|
    
 | 
						|
    MySQL.query('SELECT * FROM dj_playlists WHERE owner = ? OR is_public = 1', {Player.PlayerData.citizenid}, function(playlists)
 | 
						|
        local playlistData = {}
 | 
						|
        local remaining = #playlists
 | 
						|
        
 | 
						|
        if remaining == 0 then
 | 
						|
            return cb({})
 | 
						|
        end
 | 
						|
        
 | 
						|
        for _, playlist in pairs(playlists) do
 | 
						|
            MySQL.query('SELECT * FROM dj_playlist_songs WHERE playlist_id = ? ORDER BY position', {playlist.id}, function(songs)
 | 
						|
                table.insert(playlistData, {
 | 
						|
                    id = playlist.id,
 | 
						|
                    name = playlist.name,
 | 
						|
                    description = playlist.description,
 | 
						|
                    isPublic = playlist.is_public == 1,
 | 
						|
                    isOwner = playlist.owner == Player.PlayerData.citizenid,
 | 
						|
                    songs = songs
 | 
						|
                })
 | 
						|
                
 | 
						|
                remaining = remaining - 1
 | 
						|
                if remaining == 0 then
 | 
						|
                    cb(playlistData)
 | 
						|
                end
 | 
						|
            end)
 | 
						|
        end
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
QBCore.Functions.CreateCallback('dj:server:getSessionHistory', function(source, cb, limit)
 | 
						|
    local Player = QBCore.Functions.GetPlayer(source)
 | 
						|
    if not Player then return cb({}) end
 | 
						|
    
 | 
						|
    limit = limit or 50
 | 
						|
    
 | 
						|
    MySQL.query('SELECT * FROM dj_session_history WHERE dj_citizenid = ? ORDER BY session_start DESC LIMIT ?', {
 | 
						|
        Player.PlayerData.citizenid,
 | 
						|
        limit
 | 
						|
    }, function(history)
 | 
						|
        cb(history)
 | 
						|
    end)
 | 
						|
end)
 | 
						|
 | 
						|
-- Admin Commands
 | 
						|
QBCore.Commands.Add('djstop', 'Stoppe alle DJ-Booths (Admin)', {}, false, function(source, args)
 | 
						|
    local Player = QBCore.Functions.GetPlayer(source)
 | 
						|
    if Player.PlayerData.job.name ~= 'admin' and Player.PlayerData.job.name ~= 'police' then
 | 
						|
        TriggerClientEvent('QBCore:Notify', source, 'Du hast keine Berechtigung für diesen Befehl!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    for boothName, _ in pairs(activeDJBooths) do
 | 
						|
        -- Aktualisiere Session-Ende in der Datenbank
 | 
						|
        local djData = activeDJBooths[boothName]
 | 
						|
        if djData and djData.dj then
 | 
						|
            MySQL.update('UPDATE dj_session_history SET session_end = NOW() WHERE dj_citizenid = ? AND booth_name = ? AND session_end IS NULL', {
 | 
						|
                djData.dj.id,
 | 
						|
                boothName
 | 
						|
            })
 | 
						|
        end
 | 
						|
        
 | 
						|
        activeDJBooths[boothName] = nil
 | 
						|
        TriggerClientEvent('dj:client:stopMusic', -1, boothName)
 | 
						|
    end
 | 
						|
    
 | 
						|
    TriggerClientEvent('QBCore:Notify', source, 'Alle DJ-Booths wurden gestoppt!', 'success')
 | 
						|
    print('[DJ System] Admin ' .. GetPlayerName(source) .. ' hat alle DJ-Booths gestoppt')
 | 
						|
end)
 | 
						|
 | 
						|
QBCore.Commands.Add('djstatus', 'Zeige Status aller DJ-Booths (Admin)', {}, false, function(source, args)
 | 
						|
    local Player = QBCore.Functions.GetPlayer(source)
 | 
						|
    if Player.PlayerData.job.name ~= 'admin' and Player.PlayerData.job.name ~= 'police' then
 | 
						|
        TriggerClientEvent('QBCore:Notify', source, 'Du hast keine Berechtigung für diesen Befehl!', 'error')
 | 
						|
        return
 | 
						|
    end
 | 
						|
    
 | 
						|
    local status = {}
 | 
						|
    for boothName, boothData in pairs(activeDJBooths) do
 | 
						|
        table.insert(status, {
 | 
						|
            booth = boothName,
 | 
						|
            song = boothData.title,
 | 
						|
            dj = boothData.dj.name,
 | 
						|
            volume = boothData.volume
 | 
						|
        })
 | 
						|
    end
 | 
						|
    
 | 
						|
    if #status == 0 then
 | 
						|
        TriggerClientEvent('QBCore:Notify', source, 'Keine aktiven DJ-Booths!', 'info')
 | 
						|
    else
 | 
						|
        for _, booth in ipairs(status) do
 | 
						|
            TriggerClientEvent('QBCore:Notify', source, booth.booth .. ': ' .. booth.song .. ' (DJ: ' .. booth.dj .. ', Vol: ' .. booth.volume .. '%)', 'info')
 | 
						|
        end
 | 
						|
    end
 | 
						|
end)
 | 
						|
 | 
						|
-- Exports
 | 
						|
exports('GetActiveDJs', function()
 | 
						|
    return activeDJBooths
 | 
						|
end)
 | 
						|
 | 
						|
exports('StopBooth', function(boothName)
 | 
						|
    if activeDJBooths[boothName] then
 | 
						|
        -- Aktualisiere Session-Ende in der Datenbank
 | 
						|
        local djData = activeDJBooths[boothName]
 | 
						|
        if djData and djData.dj then
 | 
						|
            MySQL.update('UPDATE dj_session_history SET session_end = NOW() WHERE dj_citizenid = ? AND booth_name = ? AND session_end IS NULL', {
 | 
						|
                djData.dj.id,
 | 
						|
                boothName
 | 
						|
            })
 | 
						|
        end
 | 
						|
        
 | 
						|
        activeDJBooths[boothName] = nil
 | 
						|
        TriggerClientEvent('dj:client:stopMusic', -1, boothName)
 | 
						|
        return true
 | 
						|
    end
 | 
						|
    return false
 | 
						|
end)
 | 
						|
 | 
						|
-- Initialisierung
 | 
						|
print('[DJ System] Server gestartet')
 | 
						|
 |