// Улучшенный музыкальный плеер с поддержкой позиции воспроизведения const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); class EnhancedMusicPlayer { constructor() { this.currentProcess = null; this.currentTrack = null; this.currentTrackIndex = -1; this.isPlaying = false; this.isPaused = false; this.pausedPosition = 0; // Позиция в секундах где была пауза this.startTime = null; // Время начала воспроизведения this.volume = 70; this.playlist = []; // Для Windows - использование VLC или MPV для точной позиции this.playerCommand = this._detectPlayer(); console.log('[ENHANCED-MUSIC] 🎵 Музыкальный плеер инициализирован'); console.log('[ENHANCED-MUSIC] 🎮 Используемый плеер:', this.playerCommand); } // Определение доступного плеера _detectPlayer() { if (process.platform === 'win32') { // Проверяем наличие VLC const vlcPath = 'C:\\Program Files\\VideoLAN\\VLC\\vlc.exe'; const vlcPath64 = 'C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe'; if (fs.existsSync(vlcPath) || fs.existsSync(vlcPath64)) { return fs.existsSync(vlcPath) ? vlcPath : vlcPath64; } // Проверяем MPV const mpvPath = path.join(__dirname, 'tools', 'mpv.exe'); if (fs.existsSync(mpvPath)) { return mpvPath; } // Fallback на PowerShell return 'powershell'; } // Для Linux - mpv, vlc или mplayer return 'mpv'; // или 'vlc', 'mplayer' } // Остановка воспроизведения stop() { console.log('[ENHANCED-MUSIC] ⏹️ Остановка воспроизведения'); if (this.currentProcess) { try { if (this.playerCommand.includes('vlc')) { // VLC команда остановки this.currentProcess.stdin.write('quit\n'); } else if (this.playerCommand.includes('mpv')) { // MPV команда остановки this.currentProcess.stdin.write('q'); } else { // Обычное завершение процесса this.currentProcess.kill(); } } catch (err) { console.log('[ENHANCED-MUSIC] ⚠️ Ошибка при остановке:', err.message); } this.currentProcess = null; } this.isPlaying = false; this.isPaused = false; this.pausedPosition = 0; this.startTime = null; this.currentTrack = null; return this; } // Воспроизведение трека с позиции play(trackPath, startPosition = 0) { console.log('[ENHANCED-MUSIC] 🎵 Запуск воспроизведения:', trackPath, 'с позиции:', startPosition); // Останавливаем текущее воспроизведение this.stop(); if (!fs.existsSync(trackPath)) { console.error('[ENHANCED-MUSIC] ❌ Файл не найден:', trackPath); return this; } this.currentTrack = trackPath; this.startTime = Date.now() - (startPosition * 1000); let command, args; if (this.playerCommand.includes('vlc')) { // VLC с позицией воспроизведения command = this.playerCommand; args = [ '--intf', 'dummy', '--play-and-exit', '--no-video', '--start-time', startPosition.toString(), '--volume', Math.floor(this.volume * 2.56).toString(), trackPath ]; } else if (this.playerCommand.includes('mpv')) { // MPV с позицией воспроизведения command = this.playerCommand; args = [ '--no-video', '--really-quiet', '--start=' + startPosition, '--volume=' + this.volume, '--input-ipc-server=\\\\.\\pipe\\mpv-socket', trackPath ]; } else { // PowerShell fallback (без поддержки позиции) console.log('[ENHANCED-MUSIC] ⚠️ PowerShell не поддерживает возобновление с позиции'); command = 'powershell'; args = ['-WindowStyle', 'Hidden', '-Command', ` Add-Type -AssemblyName presentationCore $player = New-Object System.Windows.Media.MediaPlayer $player.Open([Uri]"${trackPath}") $player.Volume = ${this.volume / 100} Start-Sleep -Milliseconds 500 $player.Play() while ($player.Position -lt $player.NaturalDuration.TimeSpan) { Start-Sleep -Milliseconds 100 } $player.Close() `]; } // Запускаем процесс this.currentProcess = spawn(command, args, { stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true }); this.isPlaying = true; this.isPaused = false; this.currentProcess.on('close', (code) => { console.log('[ENHANCED-MUSIC] ⏹️ Воспроизведение завершено'); this.isPlaying = false; this.currentProcess = null; }); this.currentProcess.on('error', (error) => { console.error('[ENHANCED-MUSIC] ❌ Ошибка процесса:', error.message); this.isPlaying = false; this.currentProcess = null; }); return this; } // Пауза с сохранением позиции pause() { if (!this.isPlaying || this.isPaused) return this; console.log('[ENHANCED-MUSIC] ⏸️ Пауза'); // Вычисляем текущую позицию const elapsedTime = (Date.now() - this.startTime) / 1000; this.pausedPosition = elapsedTime; console.log('[ENHANCED-MUSIC] 💾 Сохранена позиция:', this.pausedPosition, 'сек'); // Останавливаем процесс if (this.currentProcess) { if (this.playerCommand.includes('vlc') || this.playerCommand.includes('mpv')) { // Для VLC/MPV отправляем команду паузы this.currentProcess.stdin.write('p'); } else { // Для других - останавливаем процесс this.currentProcess.kill(); this.currentProcess = null; } } this.isPaused = true; this.isPlaying = false; return this; } // Возобновление с сохраненной позиции resume() { if (!this.isPaused || !this.currentTrack) return this; console.log('[ENHANCED-MUSIC] ▶️ Возобновление с позиции:', this.pausedPosition, 'сек'); if (this.currentProcess && (this.playerCommand.includes('vlc') || this.playerCommand.includes('mpv'))) { // Для VLC/MPV просто снимаем с паузы this.currentProcess.stdin.write('p'); this.isPaused = false; this.isPlaying = true; } else { // Для других - запускаем заново с позиции const track = this.currentTrack; const position = this.pausedPosition; this.play(track, position); } return this; } // Установка громкости setVolume(volume) { this.volume = Math.max(0, Math.min(100, volume)); console.log('[ENHANCED-MUSIC] 🔊 Установлена громкость:', this.volume); if (this.isPlaying && this.currentProcess) { if (this.playerCommand.includes('vlc')) { // VLC команда громкости (0-256) const vlcVolume = Math.floor(this.volume * 2.56); this.currentProcess.stdin.write(`volume ${vlcVolume}\n`); } else if (this.playerCommand.includes('mpv')) { // MPV команда громкости через JSON IPC const mpvCommand = JSON.stringify({ command: ["set_property", "volume", this.volume] }); this.currentProcess.stdin.write(mpvCommand + '\n'); } } return this; } // Получение информации о плеере getPlayerInfo() { if (this.playerCommand.includes('vlc')) { return { name: 'VLC Media Player', features: ['позиция воспроизведения', 'управление громкостью', 'пауза без остановки'] }; } else if (this.playerCommand.includes('mpv')) { return { name: 'MPV Player', features: ['позиция воспроизведения', 'управление громкостью', 'пауза без остановки'] }; } else { return { name: 'Windows Media (PowerShell)', features: ['базовое воспроизведение'], limitations: ['нет сохранения позиции', 'системная громкость'] }; } } } module.exports = EnhancedMusicPlayer;