From b0f9fbee651ea961f3c72444e60c84cc12a84fbc Mon Sep 17 00:00:00 2001 From: Nordi98 Date: Sun, 3 Aug 2025 19:32:07 +0200 Subject: [PATCH] ed --- resources/[tools]/nordi_dj/html/index.html | 14 + resources/[tools]/nordi_dj/html/script.js | 360 ++++++++++++++++++++- resources/[tools]/nordi_dj/html/style.css | 252 +++++++++++++++ 3 files changed, 620 insertions(+), 6 deletions(-) diff --git a/resources/[tools]/nordi_dj/html/index.html b/resources/[tools]/nordi_dj/html/index.html index 6e7538855..50c3faf3b 100644 --- a/resources/[tools]/nordi_dj/html/index.html +++ b/resources/[tools]/nordi_dj/html/index.html @@ -123,6 +123,20 @@ + +
+
+

PLAYLISTS

+ +
+
+ +
+
+ +
diff --git a/resources/[tools]/nordi_dj/html/script.js b/resources/[tools]/nordi_dj/html/script.js index 9d2d94831..bdb97306d 100644 --- a/resources/[tools]/nordi_dj/html/script.js +++ b/resources/[tools]/nordi_dj/html/script.js @@ -91,6 +91,49 @@ function initializeDJSystem() { console.log('DJ System: Professional interface ready!'); } +function initializeDJSystem() { + console.log('DJ System: Initializing professional interface...'); + + // Initialisiere Interface-Einstellungen + initializeInterfaceSettings(); + + // Initialize audio players + djInterface.decks.A.player = document.getElementById('audio-player-a'); + djInterface.decks.B.player = document.getElementById('audio-player-b'); + + // Setup audio event listeners + setupAudioEventListeners(); + + // Initialize waveforms + initializeWaveforms(); + + // Start time display + updateTimeDisplay(); + setInterval(updateTimeDisplay, 1000); + + // Start VU meters animation + startVUMeters(); + + // Setup Interface-Kontrollen + setupInterfaceControls(); + + // Lade Playlists + loadPlaylists(); + + // Setup Playlist Event Listeners + setupPlaylistEventListeners(); + + // Event-Listener für "Neue Playlist"-Button + const createPlaylistBtn = document.getElementById('create-playlist-btn'); + if (createPlaylistBtn) { + createPlaylistBtn.addEventListener('click', createNewPlaylist); + } + + console.log('DJ System: Professional interface ready!'); +} + + + function setupEventListeners() { // Knob interactions setupKnobControls(); @@ -1410,22 +1453,40 @@ function extractYouTubeVideoId(url) { return null; } -// FiveM Integration -function notifyFiveM(event, data) { +// Verbesserte notifyFiveM-Funktion mit Callback-Unterstützung +function notifyFiveM(event, data, callback) { + const callbackId = callback ? Date.now().toString() + Math.random().toString(36).substr(2, 5) : null; + + if (callback) { + window.callbacks = window.callbacks || {}; + window.callbacks[callbackId] = callback; + } + fetch(`https://${GetParentResourceName()}/${event}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(data) + body: JSON.stringify({ + ...data, + callbackId: callbackId + }) }).catch(err => { console.error('DJ System: Failed to notify FiveM:', err); + if (callback) { + delete window.callbacks[callbackId]; + } }); } -function GetParentResourceName() { - return window.location.hostname; -} +// Callback-Handler +window.handleCallback = function(callbackId, data) { + if (window.callbacks && window.callbacks[callbackId]) { + window.callbacks[callbackId](data); + delete window.callbacks[callbackId]; + } +}; + // Message Handler for FiveM window.addEventListener('message', function(event) { @@ -1589,3 +1650,290 @@ function stopAllAudioAndCloseInterface() { stopMusic: true }); } + + +// Playlist-Verwaltung +let playlists = []; +let currentPlaylist = null; +let currentPlaylistIndex = 0; + +// Playlist laden +function loadPlaylists() { + // Lade Playlists vom Server + notifyFiveM('getPlaylists', {}, function(response) { + if (response.success && response.playlists) { + playlists = response.playlists; + updatePlaylistDisplay(); + } + }); +} + +// Playlist-Anzeige aktualisieren +function updatePlaylistDisplay() { + const playlistContainer = document.getElementById('playlist-container'); + if (!playlistContainer) return; + + playlistContainer.innerHTML = ''; + + if (playlists.length === 0) { + playlistContainer.innerHTML = '
Keine Playlists gefunden
'; + return; + } + + // Erstelle Playlist-Elemente + playlists.forEach((playlist, index) => { + const playlistElement = document.createElement('div'); + playlistElement.className = 'playlist-item'; + if (currentPlaylist && currentPlaylist.id === playlist.id) { + playlistElement.classList.add('active'); + } + + playlistElement.innerHTML = ` +
+ ${playlist.name} + ${playlist.songs.length} Songs +
+
+ + + ${playlist.isOwner ? '' : ''} +
+ `; + + // Event-Listener für Playlist-Aktionen + const playBtn = playlistElement.querySelector('.playlist-play-btn'); + if (playBtn) { + playBtn.addEventListener('click', () => playPlaylist(playlist)); + } + + const editBtn = playlistElement.querySelector('.playlist-edit-btn'); + if (editBtn) { + editBtn.addEventListener('click', () => editPlaylist(playlist)); + } + + const deleteBtn = playlistElement.querySelector('.playlist-delete-btn'); + if (deleteBtn) { + deleteBtn.addEventListener('click', () => deletePlaylist(playlist)); + } + + playlistContainer.appendChild(playlistElement); + }); +} + +// Playlist abspielen +function playPlaylist(playlist) { + if (!playlist || !playlist.songs || playlist.songs.length === 0) { + showNotification('Diese Playlist enthält keine Songs', 'warning'); + return; + } + + currentPlaylist = playlist; + currentPlaylistIndex = 0; + + // Ersten Song abspielen + playPlaylistSong(currentPlaylistIndex); +} + +// Playlist-Song abspielen +function playPlaylistSong(index) { + if (!currentPlaylist || !currentPlaylist.songs || index >= currentPlaylist.songs.length) { + showNotification('Playlist beendet', 'info'); + currentPlaylist = null; + return; + } + + const song = currentPlaylist.songs[index]; + + // Lade Song in Deck A + const trackData = { + title: song.title, + artist: song.artist || '', + url: song.url + }; + + loadTrackToPlayer('A', trackData); + + // Starte Wiedergabe + if (!djInterface.decks.A.isPlaying) { + togglePlay('A'); + } + + showNotification(`Playlist: ${currentPlaylist.name} - Song ${index + 1}/${currentPlaylist.songs.length}`, 'info'); +} + +// Nächster Song in Playlist +function playNextSong() { + if (!currentPlaylist) return; + + currentPlaylistIndex++; + if (currentPlaylistIndex < currentPlaylist.songs.length) { + playPlaylistSong(currentPlaylistIndex); + } else { + showNotification('Playlist beendet', 'info'); + currentPlaylist = null; + } +} + +// Playlist bearbeiten +function editPlaylist(playlist) { + openPlaylistEditor(playlist); +} + +// Playlist löschen +function deletePlaylist(playlist) { + if (confirm(`Möchtest du die Playlist "${playlist.name}" wirklich löschen?`)) { + notifyFiveM('deletePlaylist', { playlistId: playlist.id }, function(response) { + if (response.success) { + showNotification('Playlist gelöscht', 'success'); + loadPlaylists(); // Playlists neu laden + } else { + showNotification('Fehler beim Löschen der Playlist', 'error'); + } + }); + } +} + +// Neue Playlist erstellen +function createNewPlaylist() { + const playlistName = prompt('Name der neuen Playlist:'); + if (!playlistName) return; + + notifyFiveM('createPlaylist', { + name: playlistName, + isPublic: confirm('Soll die Playlist öffentlich sein?') + }, function(response) { + if (response.success) { + showNotification('Playlist erstellt', 'success'); + loadPlaylists(); // Playlists neu laden + } else { + showNotification('Fehler beim Erstellen der Playlist', 'error'); + } + }); +} + +// Song zu Playlist hinzufügen +function addSongToPlaylist(song, playlistId) { + notifyFiveM('addToPlaylist', { + playlistId: playlistId, + track: song + }, function(response) { + if (response.success) { + showNotification('Song zur Playlist hinzugefügt', 'success'); + loadPlaylists(); // Playlists neu laden + } else { + showNotification('Fehler beim Hinzufügen des Songs', 'error'); + } + }); +} + +// Playlist-Editor öffnen +function openPlaylistEditor(playlist) { + // Implementiere einen Playlist-Editor + // Dies könnte ein Modal sein, in dem Songs hinzugefügt/entfernt werden können + console.log('Playlist Editor für:', playlist); + + // Beispiel für ein einfaches Modal + const modal = document.createElement('div'); + modal.className = 'modal'; + modal.innerHTML = ` + + `; + + document.body.appendChild(modal); + + // Event-Listener für Modal + const closeBtn = modal.querySelector('.close-modal'); + if (closeBtn) { + closeBtn.addEventListener('click', () => { + document.body.removeChild(modal); + }); + } + + // Event-Listener für Song-Entfernung + const removeBtns = modal.querySelectorAll('.remove-song'); + removeBtns.forEach(btn => { + btn.addEventListener('click', () => { + const index = parseInt(btn.dataset.index); + removeSongFromPlaylist(playlist.id, playlist.songs[index].id); + }); + }); + + // Event-Listener für Song-Hinzufügung + const addBtn = modal.querySelector('#add-song-btn'); + if (addBtn) { + addBtn.addEventListener('click', () => { + const title = modal.querySelector('#song-title').value; + const artist = modal.querySelector('#song-artist').value; + const url = modal.querySelector('#song-url').value; + + if (!title || !url) { + showNotification('Titel und URL sind erforderlich', 'error'); + return; + } + + addSongToPlaylist({ + title: title, + artist: artist, + url: url + }, playlist.id); + + // Modal schließen + document.body.removeChild(modal); + }); + } +} + +// Song aus Playlist entfernen +function removeSongFromPlaylist(playlistId, songId) { + notifyFiveM('removeSongFromPlaylist', { + playlistId: playlistId, + songId: songId + }, function(response) { + if (response.success) { + showNotification('Song aus Playlist entfernt', 'success'); + loadPlaylists(); // Playlists neu laden + } else { + showNotification('Fehler beim Entfernen des Songs', 'error'); + } + }); +} + +// Event-Listener für Song-Ende (für Playlist-Fortsetzung) +function setupPlaylistEventListeners() { + // Wenn ein Song endet, spiele den nächsten in der Playlist + document.addEventListener('songEnded', function(e) { + if (currentPlaylist) { + playNextSong(); + } + }); +} diff --git a/resources/[tools]/nordi_dj/html/style.css b/resources/[tools]/nordi_dj/html/style.css index 5b0dd6264..75bf194b0 100644 --- a/resources/[tools]/nordi_dj/html/style.css +++ b/resources/[tools]/nordi_dj/html/style.css @@ -1454,3 +1454,255 @@ body { .p-15 { padding: 15px; } .p-20 { padding: 20px; } +/* Playlist Styles */ +.playlist-browser { + flex: 1; + display: flex; + flex-direction: column; + background: linear-gradient(145deg, #0f0f23, #1a1a2e); + border-radius: 15px; + padding: 15px; + border: 1px solid rgba(255, 255, 255, 0.1); + overflow: hidden; +} + +.browser-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 15px; + padding-bottom: 10px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.create-playlist-btn { + padding: 8px 12px; + border: none; + border-radius: 8px; + background: linear-gradient(145deg, #4ecdc4, #45b7d1); + color: #ffffff; + font-size: 12px; + font-weight: 600; + cursor: pointer; + transition: all 0.3s ease; +} + +.create-playlist-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(78, 205, 196, 0.4); +} + +.playlist-container { + flex: 1; + overflow-y: auto; + scrollbar-width: thin; + scrollbar-color: #4ecdc4 transparent; +} + +.playlist-container::-webkit-scrollbar { + width: 6px; +} + +.playlist-container::-webkit-scrollbar-track { + background: transparent; +} + +.playlist-container::-webkit-scrollbar-thumb { + background: #4ecdc4; + border-radius: 3px; +} + +.playlist-item { + padding: 10px; + margin-bottom: 8px; + background: rgba(0, 0, 0, 0.3); + border-radius: 8px; + border: 1px solid rgba(255, 255, 255, 0.05); + transition: all 0.3s ease; +} + +.playlist-item:hover { + background: rgba(78, 205, 196, 0.1); + border-color: rgba(78, 205, 196, 0.3); +} + +.playlist-item.active { + background: rgba(78, 205, 196, 0.2); + border-color: rgba(78, 205, 196, 0.5); +} + +.playlist-header { + display: flex; + justify-content: space-between; + margin-bottom: 8px; +} + +.playlist-name { + font-weight: 600; + color: #ffffff; +} + +.playlist-count { + font-size: 12px; + color: #888888; +} + +.playlist-actions { + display: flex; + gap: 8px; +} + +.playlist-actions button { + width: 30px; + height: 30px; + border: none; + border-radius: 50%; + background: rgba(0, 0, 0, 0.3); + color: #ffffff; + cursor: pointer; + transition: all 0.3s ease; +} + +.playlist-play-btn { + background: linear-gradient(145deg, #4ecdc4, #45b7d1) !important; +} + +.playlist-edit-btn { + background: linear-gradient(145deg, #feca57, #ff9ff3) !important; +} + +.playlist-delete-btn { + background: linear-gradient(145deg, #ff6b6b, #ff5722) !important; +} + +.playlist-actions button:hover { + transform: scale(1.1); +} + +.no-playlists { + text-align: center; + color: #888888; + padding: 20px; +} + +/* Playlist Editor Modal */ +.modal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.8); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; +} + +.modal-content { + background: linear-gradient(145deg, #1e1e2e, #2a2a3e); + border-radius: 20px; + padding: 20px; + width: 500px; + max-width: 90%; + max-height: 90%; + overflow-y: auto; + box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); +} + +.modal-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 15px; + padding-bottom: 10px; + border-bottom: 1px solid rgba(255, 255, 255, 0.1); +} + +.modal-header h3 { + color: #4ecdc4; + font-size: 18px; +} + +.close-modal { + width: 30px; + height: 30px; + border: none; + border-radius: 50%; + background: rgba(255, 0, 0, 0.7); + color: #ffffff; + font-size: 18px; + cursor: pointer; + transition: all 0.3s ease; +} + +.close-modal:hover { + background: rgba(255, 0, 0, 0.9); + transform: scale(1.1); +} + +.playlist-songs { + margin-bottom: 20px; + max-height: 200px; + overflow-y: auto; +} + +.playlist-song { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px; + margin-bottom: 5px; + background: rgba(0, 0, 0, 0.2); + border-radius: 5px; +} + +.remove-song { + width: 24px; + height: 24px; + border: none; + border-radius: 50%; + background: rgba(255, 0, 0, 0.7); + color: #ffffff; + cursor: pointer; +} + +.add-song-form { + padding: 15px; + background: rgba(0, 0, 0, 0.2); + border-radius: 10px; +} + +.add-song-form h4 { + margin-bottom: 10px; + color: #4ecdc4; +} + +.input-group { + margin-bottom: 10px; +} + +.input-group input { + width: 100%; + padding: 8px 12px; + border: none; + border-radius: 5px; + background: rgba(0, 0, 0, 0.3); + color: #ffffff; + outline: none; +} + +#add-song-btn { + padding: 8px 15px; + border: none; + border-radius: 5px; + background: linear-gradient(145deg, #4ecdc4, #45b7d1); + color: #ffffff; + cursor: pointer; + transition: all 0.3s ease; +} + +#add-song-btn:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(78, 205, 196, 0.4); +}