// DJ System - Professional Interface let djInterface = { decks: { A: { track: null, isPlaying: false, volume: 75, pitch: 0, cuePoint: 0, player: null, youtubePlayer: null }, B: { track: null, isPlaying: false, volume: 75, pitch: 0, cuePoint: 0, player: null, youtubePlayer: null } }, mixer: { crossfader: 50, masterVolume: 80, eq: { A: { high: 0, mid: 0, low: 0 }, B: { high: 0, mid: 0, low: 0 } } }, effects: { reverb: false, delay: false, filter: false, flanger: false, wetDry: 0 }, currentDeck: null, isRecording: false, youtubeAPIReady: false }; // YouTube API laden function loadYouTubeAPI() { // YouTube IFrame API Script laden const tag = document.createElement('script'); tag.src = 'https://www.youtube.com/iframe_api'; const firstScriptTag = document.getElementsByTagName('script')[0]; firstScriptTag.parentNode.insertBefore(tag, firstScriptTag); } // YouTube API Ready Callback window.onYouTubeIframeAPIReady = function() { console.log('DJ System: YouTube API ready'); djInterface.youtubeAPIReady = true; }; // Hier ist die fehlende Funktion function createYouTubePlayerForDeck(deck, videoId) { if (!djInterface.youtubeAPIReady) { console.error('DJ System: YouTube API not ready'); showNotification('YouTube API not ready', 'error'); return; } // Container für YouTube Player erstellen const containerId = `youtube-player-${deck.toLowerCase()}`; let container = document.getElementById(containerId); if (!container) { container = document.createElement('div'); container.id = containerId; container.style.position = 'absolute'; container.style.top = '-9999px'; container.style.left = '-9999px'; container.style.width = '1px'; container.style.height = '1px'; container.style.opacity = '0'; document.body.appendChild(container); } // Bestehenden Player zerstören, falls vorhanden if (djInterface.decks[deck].youtubePlayer) { try { djInterface.decks[deck].youtubePlayer.destroy(); } catch (e) { console.error('DJ System: Error destroying YouTube player', e); } } // Neuen Player erstellen djInterface.decks[deck].youtubePlayer = new YT.Player(containerId, { height: '1', width: '1', videoId: videoId, playerVars: { 'autoplay': 0, 'controls': 0, 'disablekb': 1, 'fs': 0, 'modestbranding': 1, 'playsinline': 1, 'rel': 0, 'showinfo': 0, 'iv_load_policy': 3, 'cc_load_policy': 0, 'origin': window.location.origin }, events: { 'onReady': function(event) { console.log(`DJ System: YouTube player ready for Deck ${deck}`); // Setze Lautstärke event.target.setVolume(djInterface.decks[deck].volume); // Generiere Waveform generateWaveform(deck, videoId); // Aktualisiere UI const vinyl = document.getElementById(`vinyl-${deck.toLowerCase()}`); if (vinyl) { vinyl.classList.add('loaded'); } }, 'onStateChange': function(event) { handleYouTubeStateChange(deck, event); }, 'onError': function(event) { handleYouTubeError(deck, event); } } }); } // YouTube State Change Handler function handleYouTubeStateChange(deck, event) { const deckData = djInterface.decks[deck]; const playBtn = document.getElementById(`play-${deck.toLowerCase()}`); const vinyl = document.getElementById(`vinyl-${deck.toLowerCase()}`); switch(event.data) { case YT.PlayerState.PLAYING: console.log(`DJ System: YouTube playing on Deck ${deck}`); deckData.isPlaying = true; if (playBtn) { playBtn.innerHTML = ''; playBtn.classList.add('playing'); } if (vinyl) { vinyl.classList.add('spinning'); } // Notify FiveM notifyFiveM('deckStateChanged', { deck: deck, isPlaying: true, track: deckData.track }); break; case YT.PlayerState.PAUSED: console.log(`DJ System: YouTube paused on Deck ${deck}`); deckData.isPlaying = false; if (playBtn) { playBtn.innerHTML = ''; playBtn.classList.remove('playing'); } if (vinyl) { vinyl.classList.remove('spinning'); } // Notify FiveM notifyFiveM('deckStateChanged', { deck: deck, isPlaying: false, track: deckData.track }); break; case YT.PlayerState.ENDED: console.log(`DJ System: YouTube ended on Deck ${deck}`); deckData.isPlaying = false; if (playBtn) { playBtn.innerHTML = ''; playBtn.classList.remove('playing'); } if (vinyl) { vinyl.classList.remove('spinning'); } // Notify FiveM notifyFiveM('songEnded', { deck: deck }); break; } } // YouTube Error Handler function handleYouTubeError(deck, event) { console.error(`DJ System: YouTube error on Deck ${deck}:`, event.data); let errorMessage = 'YouTube Fehler'; switch(event.data) { case 2: errorMessage = 'Ungültige Video ID'; break; case 5: errorMessage = 'HTML5 Player Fehler'; break; case 100: errorMessage = 'Video nicht gefunden'; break; case 101: case 150: errorMessage = 'Video nicht verfügbar (Einbettung deaktiviert)'; break; } showNotification(errorMessage, 'error'); // Notify FiveM notifyFiveM('audioError', { deck: deck, error: errorMessage }); } // Füge den Rest deines bestehenden script.js-Codes hier ein // ... // Initialize DJ Interface document.addEventListener('DOMContentLoaded', function() { initializeDJSystem(); setupEventListeners(); startAnimations(); loadYouTubeAPI(); }); // Funktion zum Extrahieren der YouTube Video ID function extractYouTubeVideoId(url) { const patterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/watch\?.*v=([^&\n?#]+)/ ]; for (let pattern of patterns) { const match = url.match(pattern); if (match && match[1]) { return match[1]; } } return null; } // Prüfe ob es eine YouTube URL ist function isYouTubeUrl(url) { const youtubePatterns = [ /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/, /youtube\.com\/watch\?.*v=([^&\n?#]+)/ ]; return youtubePatterns.some(pattern => pattern.test(url)); } // Benachrichtigungen anzeigen function showNotification(message, type = 'info') { console.log(`DJ System [${type.toUpperCase()}]: ${message}`); // Create notification element const notification = document.createElement('div'); notification.className = `notification notification-${type}`; notification.textContent = message; notification.style.cssText = ` position: fixed; top: 80px; right: 20px; padding: 15px 20px; border-radius: 10px; color: white; font-weight: 600; z-index: 10000; transform: translateX(100%); transition: transform 0.3s ease; background: ${type === 'error' ? '#ff6b6b' : type === 'success' ? '#4ecdc4' : type === 'warning' ? '#feca57' : '#45b7d1'}; box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3); `; document.body.appendChild(notification); // Animate in setTimeout(() => { notification.style.transform = 'translateX(0)'; }, 100); // Remove after 3 seconds setTimeout(() => { notification.style.transform = 'translateX(100%)'; setTimeout(() => { document.body.removeChild(notification); }, 300); }, 3000); } // FiveM benachrichtigen function notifyFiveM(event, data) { fetch(`https://${GetParentResourceName()}/${event}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }).catch(err => { console.error('DJ System: Failed to notify FiveM:', err); }); } function GetParentResourceName() { return window.location.hostname; }