1
0
Fork 0
forked from Simnation/Main
Main/resources/[tools]/nordi_dj/html/script.js
2025-08-03 16:51:12 +02:00

401 lines
11 KiB
JavaScript

let audioPlayer = null;
let currentVolume = 50;
let isPlaying = false;
let currentSong = null;
let fadeInterval = null;
// Initialize when page loads
document.addEventListener('DOMContentLoaded', function() {
audioPlayer = document.getElementById('audio-player');
setupAudioPlayer();
});
// Setup audio player with event listeners
function setupAudioPlayer() {
if (!audioPlayer) return;
// Audio Events
audioPlayer.addEventListener('loadstart', function() {
console.log('DJ System: Loading started');
});
audioPlayer.addEventListener('canplay', function() {
console.log('DJ System: Can start playing');
});
audioPlayer.addEventListener('play', function() {
console.log('DJ System: Playback started');
isPlaying = true;
});
audioPlayer.addEventListener('pause', function() {
console.log('DJ System: Playback paused');
isPlaying = false;
});
audioPlayer.addEventListener('ended', function() {
console.log('DJ System: Song ended');
isPlaying = false;
// Notify FiveM that song ended (for playlist functionality)
fetch(`https://${GetParentResourceName()}/songEnded`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: JSON.stringify({})
});
});
audioPlayer.addEventListener('error', function(e) {
console.error('DJ System: Audio error', e);
isPlaying = false;
// Notify FiveM about the error
fetch(`https://${GetParentResourceName()}/audioError`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: JSON.stringify({
error: 'Audio playback error',
code: audioPlayer.error ? audioPlayer.error.code : 'unknown'
})
});
});
audioPlayer.addEventListener('loadedmetadata', function() {
console.log('DJ System: Metadata loaded, duration:', audioPlayer.duration);
});
audioPlayer.addEventListener('timeupdate', function() {
// Optional: Send progress updates
if (isPlaying && audioPlayer.duration) {
const progress = (audioPlayer.currentTime / audioPlayer.duration) * 100;
// You can use this for progress bars if needed
}
});
}
// Main message handler from FiveM
window.addEventListener('message', function(event) {
const data = event.data;
switch(data.type) {
case 'playMusic':
playMusic(data.url, data.volume, data.title);
break;
case 'stopMusic':
stopMusic();
break;
case 'setVolume':
setVolume(data.volume);
break;
case 'fadeOut':
fadeOut();
break;
case 'fadeIn':
fadeIn();
break;
case 'pauseMusic':
pauseMusic();
break;
case 'resumeMusic':
resumeMusic();
break;
}
});
// Play music function with YouTube support
async function playMusic(url, volume, title = 'Unknown') {
if (!audioPlayer) {
console.error('DJ System: Audio player not initialized');
return;
}
try {
// Stop current music first
stopMusic();
console.log('DJ System: Attempting to play:', title, url);
// Set volume
currentVolume = volume || 50;
audioPlayer.volume = currentVolume / 100;
// Handle different URL types
let playableUrl = await processUrl(url);
if (!playableUrl) {
console.error('DJ System: Could not process URL:', url);
notifyError('Could not process audio URL');
return;
}
// Set source and play
audioPlayer.src = playableUrl;
audioPlayer.load();
// Store current song info
currentSong = {
title: title,
url: url,
playableUrl: playableUrl
};
// Attempt to play
const playPromise = audioPlayer.play();
if (playPromise !== undefined) {
playPromise
.then(() => {
console.log('DJ System: Successfully started playing:', title);
isPlaying = true;
})
.catch(error => {
console.error('DJ System: Play failed:', error);
notifyError('Playback failed: ' + error.message);
});
}
} catch (error) {
console.error('DJ System: Error in playMusic:', error);
notifyError('Error playing music: ' + error.message);
}
}
// Process different URL types
async function processUrl(url) {
try {
// Check if it's a YouTube URL
if (isYouTubeUrl(url)) {
console.log('DJ System: Processing YouTube URL');
return await convertYouTubeUrl(url);
}
// Check if it's a direct audio URL
if (isDirectAudioUrl(url)) {
console.log('DJ System: Direct audio URL detected');
return url;
}
// Try to use URL as-is (might be pre-converted)
console.log('DJ System: Using URL as-is');
return url;
} catch (error) {
console.error('DJ System: Error processing URL:', error);
return null;
}
}
// Check if URL is YouTube
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));
}
// Check if URL is direct audio
function isDirectAudioUrl(url) {
const audioExtensions = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac'];
const lowerUrl = url.toLowerCase();
return audioExtensions.some(ext => lowerUrl.includes(ext)) ||
lowerUrl.includes('audio/') ||
lowerUrl.includes('stream');
}
// Convert YouTube URL (this would be handled server-side in real implementation)
async function convertYouTubeUrl(url) {
try {
// Extract video ID
const videoId = extractYouTubeVideoId(url);
if (!videoId) {
throw new Error('Could not extract YouTube video ID');
}
console.log('DJ System: YouTube Video ID:', videoId);
// In a real implementation, this would call your server-side converter
// For now, we'll return the original URL and let the server handle it
return url;
} catch (error) {
console.error('DJ System: YouTube conversion error:', error);
return null;
}
}
// Extract 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;
}
// Stop music
function stopMusic() {
if (!audioPlayer) return;
try {
audioPlayer.pause();
audioPlayer.currentTime = 0;
audioPlayer.src = '';
isPlaying = false;
currentSong = null;
// Clear any fade effects
if (fadeInterval) {
clearInterval(fadeInterval);
fadeInterval = null;
}
console.log('DJ System: Music stopped');
} catch (error) {
console.error('DJ System: Error stopping music:', error);
}
}
// Pause music
function pauseMusic() {
if (!audioPlayer || !isPlaying) return;
try {
audioPlayer.pause();
isPlaying = false;
console.log('DJ System: Music paused');
} catch (error) {
console.error('DJ System: Error pausing music:', error);
}
}
// Resume music
function resumeMusic() {
if (!audioPlayer || isPlaying) return;
try {
const playPromise = audioPlayer.play();
if (playPromise !== undefined) {
playPromise
.then(() => {
isPlaying = true;
console.log('DJ System: Music resumed');
})
.catch(error => {
console.error('DJ System: Resume failed:', error);
});
}
} catch (error) {
console.error('DJ System: Error resuming music:', error);
}
}
// Set volume
function setVolume(volume) {
if (!audioPlayer) return;
try {
currentVolume = Math.max(0, Math.min(100, volume));
audioPlayer.volume = currentVolume / 100;
console.log('DJ System: Volume set to', currentVolume + '%');
} catch (error) {
console.error('DJ System: Error setting volume:', error);
}
}
// Fade out effect (when player moves away)
function fadeOut() {
if (!audioPlayer || !isPlaying) return;
if (fadeInterval) {
clearInterval(fadeInterval);
}
let currentVol = audioPlayer.volume;
const targetVol = 0;
const fadeStep = 0.05;
fadeInterval = setInterval(() => {
currentVol -= fadeStep;
if (currentVol <= targetVol) {
currentVol = targetVol;
audioPlayer.volume = currentVol;
clearInterval(fadeInterval);
fadeInterval = null;
} else {
audioPlayer.volume = currentVol;
}
}, 50);
}
// Fade in effect (when player moves closer)
function fadeIn() {
if (!audioPlayer || !isPlaying) return;
if (fadeInterval) {
clearInterval(fadeInterval);
}
let currentVol = audioPlayer.volume;
const targetVol = currentVolume / 100;
const fadeStep = 0.05;
fadeInterval = setInterval(() => {
currentVol += fadeStep;
if (currentVol >= targetVol) {
currentVol = targetVol;
audioPlayer.volume = currentVol;
clearInterval(fadeInterval);
fadeInterval = null;
} else {
audioPlayer.volume = currentVol;
}
}, 50);
}
// Notify FiveM about errors
function notifyError(message) {
fetch(`https://${GetParentResourceName()}/audioError`, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
},
body: JSON.stringify({
error: message
})
}).catch(err => {
console.error('DJ System: Failed to notify error:', err);
});
}
// Get current resource name
function GetParentResourceName() {
return window.location.hostname;
}
// Debug functions (can be called from browser console)
window.djDebug = {
getCurrentSong: () => currentSong,
getVolume: () => currentVolume,
isPlaying: () => isPlaying,
getAudioPlayer: () => audioPlayer,
testPlay: (url) => playMusic(url, 50, 'Test Song'),
testStop: () => stopMusic(),
testVolume: (vol) => setVolume(vol)
};
// Log when script is loaded
console.log('DJ System: Script loaded and ready');