// Радио плеер через Node.js с поддержкой HTTP потоков const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); const http = require('http'); const https = require('https'); class RadioStreamPlayer { constructor() { this.isPlaying = false; this.volume = 70; this.currentUrl = null; this.ffplayProcess = null; this.vlcProcess = null; this.mpvProcess = null; } play(url) { this.stop(); // Добавляем протокол если его нет if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'http://' + url; } console.log('[RADIO] 🎵 Запуск радио потока:', url); this.currentUrl = url; // Пробуем разные плееры в порядке предпочтения this._tryMpv(url) || this._tryVlc(url) || this._tryFfplay(url) || this._tryPowerShell(url); } _tryMpv(url) { try { const mpvPath = path.join(__dirname, 'tools', 'mpv.exe'); if (!fs.existsSync(mpvPath)) { console.log('[RADIO] MPV не найден'); return false; } console.log('[RADIO] Запуск через MPV'); this.mpvProcess = spawn(mpvPath, [ '--no-video', '--volume=' + this.volume, '--no-terminal', url ]); this.mpvProcess.on('error', (err) => { console.error('[RADIO] MPV ошибка:', err.message); this.isPlaying = false; }); this.mpvProcess.on('exit', (code) => { console.log('[RADIO] MPV завершен с кодом:', code); this.isPlaying = false; }); this.isPlaying = true; return true; } catch (err) { console.error('[RADIO] Ошибка MPV:', err.message); return false; } } _tryVlc(url) { try { const vlcPaths = [ path.join(__dirname, 'tools', 'vlc.exe'), 'C:\\Program Files\\VideoLAN\\VLC\\vlc.exe', 'C:\\Program Files (x86)\\VideoLAN\\VLC\\vlc.exe' ]; let vlcPath = null; for (const p of vlcPaths) { if (fs.existsSync(p)) { vlcPath = p; break; } } if (!vlcPath) { console.log('[RADIO] VLC не найден'); return false; } console.log('[RADIO] Запуск через VLC'); this.vlcProcess = spawn(vlcPath, [ '--intf', 'dummy', '--no-video', '--volume', Math.floor(this.volume * 2.56).toString(), url ]); this.vlcProcess.on('error', (err) => { console.error('[RADIO] VLC ошибка:', err.message); this.isPlaying = false; }); this.vlcProcess.on('exit', (code) => { console.log('[RADIO] VLC завершен с кодом:', code); this.isPlaying = false; }); this.isPlaying = true; return true; } catch (err) { console.error('[RADIO] Ошибка VLC:', err.message); return false; } } _tryFfplay(url) { try { const ffplayPath = path.join(__dirname, 'tools', 'ffplay.exe'); if (!fs.existsSync(ffplayPath)) { console.log('[RADIO] ffplay не найден'); return false; } console.log('[RADIO] Запуск через ffplay'); this.ffplayProcess = spawn(ffplayPath, [ '-nodisp', '-volume', this.volume.toString(), '-autoexit', url ]); this.ffplayProcess.on('error', (err) => { console.error('[RADIO] ffplay ошибка:', err.message); this.isPlaying = false; }); this.ffplayProcess.on('exit', (code) => { console.log('[RADIO] ffplay завершен с кодом:', code); this.isPlaying = false; }); this.isPlaying = true; return true; } catch (err) { console.error('[RADIO] Ошибка ffplay:', err.message); return false; } } _tryPowerShell(url) { try { console.log('[RADIO] Запуск через PowerShell и Windows Media Player'); const script = ` Add-Type -AssemblyName presentationCore $player = New-Object System.Windows.Media.MediaPlayer $player.Volume = ${this.volume / 100} $player.Open([Uri]"${url}") $player.Play() # Держим процесс активным while ($player.HasAudio -or $player.NaturalDuration.TimeSpan.TotalSeconds -eq 0) { Start-Sleep -Milliseconds 100 } `; spawn('powershell', ['-Command', script]); this.isPlaying = true; return true; } catch (err) { console.error('[RADIO] Ошибка PowerShell:', err.message); return false; } } stop() { console.log('[RADIO] ⏹️ Остановка радио'); if (this.mpvProcess) { this.mpvProcess.kill(); this.mpvProcess = null; } if (this.vlcProcess) { this.vlcProcess.kill(); this.vlcProcess = null; } if (this.ffplayProcess) { this.ffplayProcess.kill(); this.ffplayProcess = null; } // Убиваем любые оставшиеся процессы spawn('taskkill', ['/F', '/IM', 'mpv.exe'], { stdio: 'ignore' }); spawn('taskkill', ['/F', '/IM', 'vlc.exe'], { stdio: 'ignore' }); spawn('taskkill', ['/F', '/IM', 'ffplay.exe'], { stdio: 'ignore' }); this.isPlaying = false; this.currentUrl = null; } setVolume(volume) { this.volume = Math.max(0, Math.min(100, volume)); console.log('[RADIO] 🔊 Установка громкости:', this.volume); // Для изменения громкости нужно перезапустить if (this.isPlaying && this.currentUrl) { const url = this.currentUrl; this.stop(); setTimeout(() => this.play(url), 500); } } getStatus() { return { isPlaying: this.isPlaying, currentUrl: this.currentUrl, volume: this.volume }; } } module.exports = RadioStreamPlayer;