forked from Simnation/Main
ed
This commit is contained in:
parent
9a29e35e64
commit
cac2b97954
4 changed files with 338 additions and 360 deletions
|
@ -622,7 +622,7 @@ local function extractVideoId(url)
|
|||
return nil
|
||||
end
|
||||
|
||||
-- Aktualisiere die PlayMusic Funktion
|
||||
-- Aktualisierte PlayMusic Funktion
|
||||
function PlayMusic(title, url, volume)
|
||||
if not title or not url then
|
||||
lib.notify({
|
||||
|
@ -633,29 +633,31 @@ function PlayMusic(title, url, volume)
|
|||
return
|
||||
end
|
||||
|
||||
-- Bereinige YouTube URL
|
||||
local cleanedUrl = cleanYouTubeUrl(url)
|
||||
local videoId = extractVideoId(cleanedUrl)
|
||||
-- Bereinige URL von Playlist-Parametern
|
||||
local cleanUrl = url
|
||||
if string.find(url, "youtube") then
|
||||
cleanUrl = string.gsub(url, "&list=.-$", "")
|
||||
cleanUrl = string.gsub(cleanUrl, "&start_radio=.-$", "")
|
||||
cleanUrl = string.gsub(cleanUrl, "&index=.-$", "")
|
||||
|
||||
if videoId then
|
||||
lib.notify({
|
||||
title = 'DJ System',
|
||||
description = 'YouTube Video wird geladen: ' .. title,
|
||||
description = 'YouTube Video wird gestreamt: ' .. title,
|
||||
type = 'info'
|
||||
})
|
||||
|
||||
print('[DJ System] YouTube Video ID: ' .. videoId)
|
||||
print('[DJ System] Bereinigte URL: ' .. cleanedUrl)
|
||||
end
|
||||
|
||||
print('[DJ System] Streaming: ' .. title .. ' | Clean URL: ' .. cleanUrl)
|
||||
|
||||
-- Sende an Server
|
||||
TriggerServerEvent('dj:playMusic', title, cleanedUrl, volume or 50)
|
||||
TriggerServerEvent('dj:playMusic', title, cleanUrl, volume or 50)
|
||||
|
||||
-- Update lokale Variablen
|
||||
isPlaying = true
|
||||
currentSong = {
|
||||
title = title,
|
||||
url = cleanedUrl,
|
||||
url = cleanUrl,
|
||||
volume = volume or 50
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -3,30 +3,21 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>DJ System</title>
|
||||
<title>DJ System - YouTube Streaming</title>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="music-player">
|
||||
<!-- Normaler Audio Player für direkte URLs -->
|
||||
<audio
|
||||
id="audio-player"
|
||||
preload="auto"
|
||||
crossorigin="anonymous"
|
||||
controls="false"
|
||||
style="display: none;">
|
||||
Dein Browser unterstützt das Audio-Element nicht.
|
||||
</audio>
|
||||
|
||||
<!-- Optional: Progress indicator (hidden by default) -->
|
||||
<div id="progress-container" style="display: none;">
|
||||
<div id="progress-bar"></div>
|
||||
</div>
|
||||
|
||||
<!-- Optional: Song info display (hidden by default) -->
|
||||
<div id="song-info" style="display: none;">
|
||||
<span id="song-title"></span>
|
||||
<span id="song-time"></span>
|
||||
</div>
|
||||
<!-- YouTube Player wird dynamisch erstellt -->
|
||||
<!-- Container wird von JavaScript erstellt -->
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
|
|
|
@ -4,78 +4,152 @@ let isPlaying = false;
|
|||
let currentSong = null;
|
||||
let fadeInterval = null;
|
||||
|
||||
// YouTube Player API laden
|
||||
let youtubeAPIReady = false;
|
||||
let youtubePlayer = null;
|
||||
|
||||
// Initialize when page loads
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
audioPlayer = document.getElementById('audio-player');
|
||||
loadYouTubeAPI();
|
||||
setupAudioPlayer();
|
||||
});
|
||||
|
||||
// Setup audio player with event listeners
|
||||
function setupAudioPlayer() {
|
||||
if (!audioPlayer) return;
|
||||
// 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);
|
||||
}
|
||||
|
||||
// Audio Events
|
||||
audioPlayer.addEventListener('loadstart', function() {
|
||||
console.log('DJ System: Loading started');
|
||||
// YouTube API Ready Callback
|
||||
window.onYouTubeIframeAPIReady = function() {
|
||||
console.log('DJ System: YouTube API ready');
|
||||
youtubeAPIReady = true;
|
||||
|
||||
// Erstelle versteckten YouTube Player
|
||||
createYouTubePlayer();
|
||||
};
|
||||
|
||||
// YouTube Player erstellen
|
||||
function createYouTubePlayer() {
|
||||
// Container für YouTube Player
|
||||
const playerContainer = document.createElement('div');
|
||||
playerContainer.id = 'youtube-player-container';
|
||||
playerContainer.style.position = 'absolute';
|
||||
playerContainer.style.top = '-9999px';
|
||||
playerContainer.style.left = '-9999px';
|
||||
playerContainer.style.width = '1px';
|
||||
playerContainer.style.height = '1px';
|
||||
playerContainer.style.opacity = '0';
|
||||
document.body.appendChild(playerContainer);
|
||||
|
||||
youtubePlayer = new YT.Player('youtube-player-container', {
|
||||
height: '1',
|
||||
width: '1',
|
||||
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,
|
||||
'start': 0,
|
||||
'origin': window.location.origin
|
||||
},
|
||||
events: {
|
||||
'onReady': onYouTubePlayerReady,
|
||||
'onStateChange': onYouTubePlayerStateChange,
|
||||
'onError': onYouTubePlayerError
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
audioPlayer.addEventListener('canplay', function() {
|
||||
console.log('DJ System: Can start playing');
|
||||
});
|
||||
function onYouTubePlayerReady(event) {
|
||||
console.log('DJ System: YouTube Player ready');
|
||||
}
|
||||
|
||||
audioPlayer.addEventListener('play', function() {
|
||||
console.log('DJ System: Playback started');
|
||||
function onYouTubePlayerStateChange(event) {
|
||||
switch(event.data) {
|
||||
case YT.PlayerState.PLAYING:
|
||||
console.log('DJ System: YouTube playing');
|
||||
isPlaying = true;
|
||||
});
|
||||
|
||||
audioPlayer.addEventListener('pause', function() {
|
||||
console.log('DJ System: Playback paused');
|
||||
break;
|
||||
case YT.PlayerState.PAUSED:
|
||||
console.log('DJ System: YouTube paused');
|
||||
isPlaying = false;
|
||||
});
|
||||
|
||||
audioPlayer.addEventListener('ended', function() {
|
||||
console.log('DJ System: Song ended');
|
||||
break;
|
||||
case YT.PlayerState.ENDED:
|
||||
console.log('DJ System: YouTube 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({})
|
||||
});
|
||||
notifyFiveM('songEnded', {});
|
||||
break;
|
||||
case YT.PlayerState.BUFFERING:
|
||||
console.log('DJ System: YouTube buffering');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function onYouTubePlayerError(event) {
|
||||
console.error('DJ System: YouTube error:', 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;
|
||||
}
|
||||
|
||||
notifyFiveM('audioError', { error: errorMessage });
|
||||
}
|
||||
|
||||
// Setup normaler Audio Player für direkte URLs
|
||||
function setupAudioPlayer() {
|
||||
audioPlayer = document.getElementById('audio-player');
|
||||
if (!audioPlayer) {
|
||||
audioPlayer = document.createElement('audio');
|
||||
audioPlayer.id = 'audio-player';
|
||||
audioPlayer.style.display = 'none';
|
||||
document.body.appendChild(audioPlayer);
|
||||
}
|
||||
|
||||
audioPlayer.addEventListener('play', () => {
|
||||
isPlaying = true;
|
||||
console.log('DJ System: Audio playing');
|
||||
});
|
||||
|
||||
audioPlayer.addEventListener('error', function(e) {
|
||||
audioPlayer.addEventListener('pause', () => {
|
||||
isPlaying = false;
|
||||
console.log('DJ System: Audio paused');
|
||||
});
|
||||
|
||||
audioPlayer.addEventListener('ended', () => {
|
||||
isPlaying = false;
|
||||
notifyFiveM('songEnded', {});
|
||||
});
|
||||
|
||||
audioPlayer.addEventListener('error', (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
|
||||
}
|
||||
notifyFiveM('audioError', { error: 'Audio playback error' });
|
||||
});
|
||||
}
|
||||
|
||||
// Main message handler from FiveM
|
||||
// Main message handler
|
||||
window.addEventListener('message', function(event) {
|
||||
const data = event.data;
|
||||
|
||||
|
@ -89,12 +163,6 @@ window.addEventListener('message', function(event) {
|
|||
case 'setVolume':
|
||||
setVolume(data.volume);
|
||||
break;
|
||||
case 'fadeOut':
|
||||
fadeOut();
|
||||
break;
|
||||
case 'fadeIn':
|
||||
fadeIn();
|
||||
break;
|
||||
case 'pauseMusic':
|
||||
pauseMusic();
|
||||
break;
|
||||
|
@ -104,90 +172,158 @@ window.addEventListener('message', function(event) {
|
|||
}
|
||||
});
|
||||
|
||||
// Play music function with YouTube support
|
||||
// Musik abspielen - YouTube oder direkte URL
|
||||
async function playMusic(url, volume, title = 'Unknown') {
|
||||
if (!audioPlayer) {
|
||||
console.error('DJ System: Audio player not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Stop current music first
|
||||
console.log('DJ System: Playing:', title, url);
|
||||
|
||||
// Stoppe aktuelle Musik
|
||||
stopMusic();
|
||||
|
||||
console.log('DJ System: Attempting to play:', title, url);
|
||||
|
||||
// Set volume
|
||||
// Setze Lautstärke
|
||||
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;
|
||||
// Prüfe ob YouTube URL
|
||||
if (isYouTubeUrl(url)) {
|
||||
await playYouTubeMusic(url, volume, title);
|
||||
} else {
|
||||
await playDirectMusic(url, volume, title);
|
||||
}
|
||||
|
||||
// Set source and play
|
||||
audioPlayer.src = playableUrl;
|
||||
audioPlayer.load();
|
||||
|
||||
// Store current song info
|
||||
// Speichere aktuelle Song Info
|
||||
currentSong = {
|
||||
title: title,
|
||||
url: url,
|
||||
playableUrl: playableUrl
|
||||
volume: volume
|
||||
};
|
||||
|
||||
// Attempt to play
|
||||
const playPromise = audioPlayer.play();
|
||||
} catch (error) {
|
||||
console.error('DJ System: Error playing music:', error);
|
||||
notifyFiveM('audioError', { error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
// YouTube Musik abspielen
|
||||
async function playYouTubeMusic(url, volume, title) {
|
||||
if (!youtubeAPIReady || !youtubePlayer) {
|
||||
throw new Error('YouTube Player nicht bereit');
|
||||
}
|
||||
|
||||
const videoId = extractYouTubeVideoId(url);
|
||||
if (!videoId) {
|
||||
throw new Error('Ungültige YouTube URL');
|
||||
}
|
||||
|
||||
console.log('DJ System: Playing YouTube video:', videoId);
|
||||
|
||||
// Lade und spiele YouTube Video
|
||||
youtubePlayer.loadVideoById({
|
||||
videoId: videoId,
|
||||
startSeconds: 0
|
||||
});
|
||||
|
||||
// Setze Lautstärke
|
||||
youtubePlayer.setVolume(volume || 50);
|
||||
|
||||
// Warte kurz und starte
|
||||
setTimeout(() => {
|
||||
youtubePlayer.playVideo();
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('DJ System: Error in playMusic:', error);
|
||||
notifyError('Error playing music: ' + error.message);
|
||||
// Direkte Audio URL abspielen
|
||||
async function playDirectMusic(url, volume, title) {
|
||||
if (!audioPlayer) {
|
||||
throw new Error('Audio Player nicht verfügbar');
|
||||
}
|
||||
|
||||
console.log('DJ System: Playing direct audio:', url);
|
||||
|
||||
audioPlayer.src = url;
|
||||
audioPlayer.volume = (volume || 50) / 100;
|
||||
audioPlayer.load();
|
||||
|
||||
const playPromise = audioPlayer.play();
|
||||
if (playPromise !== undefined) {
|
||||
await playPromise;
|
||||
}
|
||||
}
|
||||
|
||||
// Process different URL types
|
||||
async function processUrl(url) {
|
||||
// Musik stoppen
|
||||
function stopMusic() {
|
||||
try {
|
||||
// Check if it's a YouTube URL
|
||||
if (isYouTubeUrl(url)) {
|
||||
console.log('DJ System: Processing YouTube URL');
|
||||
return await convertYouTubeUrl(url);
|
||||
// Stoppe YouTube Player
|
||||
if (youtubePlayer && youtubeAPIReady) {
|
||||
youtubePlayer.stopVideo();
|
||||
}
|
||||
|
||||
// Check if it's a direct audio URL
|
||||
if (isDirectAudioUrl(url)) {
|
||||
console.log('DJ System: Direct audio URL detected');
|
||||
return url;
|
||||
// Stoppe Audio Player
|
||||
if (audioPlayer) {
|
||||
audioPlayer.pause();
|
||||
audioPlayer.currentTime = 0;
|
||||
audioPlayer.src = '';
|
||||
}
|
||||
|
||||
// Try to use URL as-is (might be pre-converted)
|
||||
console.log('DJ System: Using URL as-is');
|
||||
return url;
|
||||
isPlaying = false;
|
||||
currentSong = null;
|
||||
|
||||
console.log('DJ System: Music stopped');
|
||||
|
||||
} catch (error) {
|
||||
console.error('DJ System: Error processing URL:', error);
|
||||
return null;
|
||||
console.error('DJ System: Error stopping music:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if URL is YouTube
|
||||
// Musik pausieren
|
||||
function pauseMusic() {
|
||||
try {
|
||||
if (currentSong && isYouTubeUrl(currentSong.url)) {
|
||||
if (youtubePlayer && youtubeAPIReady) {
|
||||
youtubePlayer.pauseVideo();
|
||||
}
|
||||
} else if (audioPlayer) {
|
||||
audioPlayer.pause();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('DJ System: Error pausing music:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Musik fortsetzen
|
||||
function resumeMusic() {
|
||||
try {
|
||||
if (currentSong && isYouTubeUrl(currentSong.url)) {
|
||||
if (youtubePlayer && youtubeAPIReady) {
|
||||
youtubePlayer.playVideo();
|
||||
}
|
||||
} else if (audioPlayer) {
|
||||
audioPlayer.play();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('DJ System: Error resuming music:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Lautstärke setzen
|
||||
function setVolume(volume) {
|
||||
try {
|
||||
currentVolume = Math.max(0, Math.min(100, volume));
|
||||
|
||||
if (currentSong && isYouTubeUrl(currentSong.url)) {
|
||||
if (youtubePlayer && youtubeAPIReady) {
|
||||
youtubePlayer.setVolume(currentVolume);
|
||||
}
|
||||
} else if (audioPlayer) {
|
||||
audioPlayer.volume = currentVolume / 100;
|
||||
}
|
||||
|
||||
console.log('DJ System: Volume set to', currentVolume + '%');
|
||||
} catch (error) {
|
||||
console.error('DJ System: Error setting volume:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// YouTube URL prüfen
|
||||
function isYouTubeUrl(url) {
|
||||
const youtubePatterns = [
|
||||
/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/,
|
||||
|
@ -197,38 +333,7 @@ function isYouTubeUrl(url) {
|
|||
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
|
||||
// YouTube Video ID extrahieren
|
||||
function extractYouTubeVideoId(url) {
|
||||
const patterns = [
|
||||
/(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([^&\n?#]+)/,
|
||||
|
@ -245,157 +350,30 @@ function extractYouTubeVideoId(url) {
|
|||
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`, {
|
||||
// FiveM benachrichtigen
|
||||
function notifyFiveM(event, data) {
|
||||
fetch(`https://${GetParentResourceName()}/` + event, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json; charset=UTF-8',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
error: message
|
||||
})
|
||||
body: JSON.stringify(data)
|
||||
}).catch(err => {
|
||||
console.error('DJ System: Failed to notify error:', err);
|
||||
console.error('DJ System: Failed to notify FiveM:', err);
|
||||
});
|
||||
}
|
||||
|
||||
// Get current resource name
|
||||
function GetParentResourceName() {
|
||||
return window.location.hostname;
|
||||
}
|
||||
|
||||
// Debug functions (can be called from browser console)
|
||||
// Debug
|
||||
window.djDebug = {
|
||||
getCurrentSong: () => currentSong,
|
||||
getVolume: () => currentVolume,
|
||||
isPlaying: () => isPlaying,
|
||||
getAudioPlayer: () => audioPlayer,
|
||||
testPlay: (url) => playMusic(url, 50, 'Test Song'),
|
||||
testStop: () => stopMusic(),
|
||||
testVolume: (vol) => setVolume(vol)
|
||||
youtubeReady: () => youtubeAPIReady,
|
||||
testYouTube: (videoId) => playYouTubeMusic('https://www.youtube.com/watch?v=' + videoId, 50, 'Test')
|
||||
};
|
||||
|
||||
// Log when script is loaded
|
||||
console.log('DJ System: Script loaded and ready');
|
||||
console.log('DJ System: YouTube streaming system loaded');
|
||||
|
|
|
@ -360,54 +360,61 @@ local function useAlternativeConversion(originalUrl, videoId, callback)
|
|||
end)
|
||||
end
|
||||
|
||||
-- Aktualisiere die PlayMusic Funktion
|
||||
-- Aktualisierte PlayMusic Funktion
|
||||
RegisterServerEvent('dj:playMusic')
|
||||
AddEventHandler('dj:playMusic', function(title, url, volume)
|
||||
local src = source
|
||||
local Player = QBCore.Functions.GetPlayer(src)
|
||||
if not Player then return end
|
||||
|
||||
print('[DJ System] Spiele Musik ab: ' .. title .. ' | URL: ' .. url)
|
||||
-- Bereinige YouTube URL (entferne Playlist-Parameter)
|
||||
local cleanUrl = url
|
||||
if string.find(url, "youtube%.com") or string.find(url, "youtu%.be") then
|
||||
-- Entferne &list= und andere Parameter
|
||||
cleanUrl = string.gsub(url, "&list=.-$", "")
|
||||
cleanUrl = string.gsub(cleanUrl, "&start_radio=.-$", "")
|
||||
cleanUrl = string.gsub(cleanUrl, "&index=.-$", "")
|
||||
|
||||
-- Prüfe ob es eine YouTube URL ist
|
||||
if string.match(url, "youtube%.com") or string.match(url, "youtu%.be") then
|
||||
convertYouTubeUrl(url, function(convertedUrl, error)
|
||||
if error then
|
||||
TriggerClientEvent('QBCore:Notify', src, 'Fehler beim Konvertieren: ' .. error, 'error')
|
||||
return
|
||||
print('[DJ System] Bereinigte YouTube URL: ' .. cleanUrl)
|
||||
end
|
||||
|
||||
if convertedUrl then
|
||||
-- Sende konvertierte URL an alle Clients
|
||||
TriggerClientEvent('dj:playMusicClient', -1, title, convertedUrl, volume)
|
||||
print('[DJ System] Streaming: ' .. title .. ' | URL: ' .. cleanUrl)
|
||||
|
||||
-- Sende direkt an alle Clients zum Streamen
|
||||
TriggerClientEvent('dj:playMusicClient', -1, title, cleanUrl, volume)
|
||||
|
||||
-- Speichere in Datenbank
|
||||
local songType = 'direct'
|
||||
if string.find(cleanUrl, "youtube") then
|
||||
songType = 'youtube'
|
||||
end
|
||||
|
||||
-- Speichere in Session History
|
||||
MySQL.Async.execute('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,
|
||||
'Unknown', -- Du kannst hier den Booth-Namen hinzufügen
|
||||
'DJ Booth',
|
||||
title,
|
||||
url,
|
||||
'youtube',
|
||||
cleanUrl,
|
||||
songType,
|
||||
volume
|
||||
})
|
||||
else
|
||||
TriggerClientEvent('QBCore:Notify', src, 'Konvertierung fehlgeschlagen', 'error')
|
||||
end
|
||||
end)
|
||||
else
|
||||
-- Direkte Audio URL
|
||||
TriggerClientEvent('dj:playMusicClient', -1, title, url, volume)
|
||||
|
||||
-- Speichere in Session History
|
||||
MySQL.Async.execute('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,
|
||||
'Unknown',
|
||||
title,
|
||||
url,
|
||||
'direct',
|
||||
volume
|
||||
})
|
||||
end
|
||||
TriggerClientEvent('QBCore:Notify', src, 'Streaming: ' .. title, 'success')
|
||||
end)
|
||||
|
||||
-- Audio Error Handler
|
||||
RegisterNUICallback('audioError', function(data, cb)
|
||||
local src = source
|
||||
print('[DJ System] Audio Error: ' .. (data.error or 'Unknown'))
|
||||
|
||||
TriggerClientEvent('QBCore:Notify', src, 'Audio Fehler: ' .. (data.error or 'Unbekannt'), 'error')
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
-- Song Ended Handler
|
||||
RegisterNUICallback('songEnded', function(data, cb)
|
||||
print('[DJ System] Song ended')
|
||||
-- Hier könntest du Playlist-Logik hinzufügen
|
||||
cb('ok')
|
||||
end)
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue