1
0
Fork 0
forked from Simnation/Main
This commit is contained in:
Nordi98 2025-08-03 19:32:07 +02:00
parent 585ee069c2
commit b0f9fbee65
3 changed files with 620 additions and 6 deletions

View file

@ -123,6 +123,20 @@
</div>
</div>
<div class="playlist-browser">
<div class="browser-header">
<h4>PLAYLISTS</h4>
<button id="create-playlist-btn" class="create-playlist-btn">
<i class="fas fa-plus"></i> Neue Playlist
</button>
</div>
<div id="playlist-container" class="playlist-container">
<!-- Playlists werden hier dynamisch eingefügt -->
</div>
</div>
<!-- Channel Controls -->
<div class="channel-controls">
<!-- Channel A -->

View file

@ -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 = '<div class="no-playlists">Keine Playlists gefunden</div>';
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 = `
<div class="playlist-header">
<span class="playlist-name">${playlist.name}</span>
<span class="playlist-count">${playlist.songs.length} Songs</span>
</div>
<div class="playlist-actions">
<button class="playlist-play-btn" title="Play"><i class="fas fa-play"></i></button>
<button class="playlist-edit-btn" title="Edit"><i class="fas fa-edit"></i></button>
${playlist.isOwner ? '<button class="playlist-delete-btn" title="Delete"><i class="fas fa-trash"></i></button>' : ''}
</div>
`;
// 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 = `
<div class="modal-content">
<div class="modal-header">
<h3>Playlist bearbeiten: ${playlist.name}</h3>
<button class="close-modal">×</button>
</div>
<div class="modal-body">
<div class="playlist-songs">
${playlist.songs.map((song, idx) => `
<div class="playlist-song">
<span>${idx + 1}. ${song.title}</span>
<button class="remove-song" data-index="${idx}">
<i class="fas fa-times"></i>
</button>
</div>
`).join('')}
</div>
<div class="add-song-form">
<h4>Song hinzufügen</h4>
<div class="input-group">
<input type="text" id="song-title" placeholder="Titel">
</div>
<div class="input-group">
<input type="text" id="song-artist" placeholder="Künstler (optional)">
</div>
<div class="input-group">
<input type="text" id="song-url" placeholder="URL (YouTube oder direkt)">
</div>
<button id="add-song-btn">Song hinzufügen</button>
</div>
</div>
</div>
`;
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();
}
});
}

View file

@ -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);
}