// Улучшенный радио плеер с точным управлением громкостью процесса const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); class ImprovedRadioPlayer { constructor() { this.radioProcess = null; this.isPlaying = false; this.volume = 70; this.currentUrl = null; this.playerPid = null; this.volumeControlInterval = null; } play(url) { this.stop(); // Добавляем протокол если его нет if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'http://' + url; } console.log('[RADIO] 📻 Запуск радио:', url); this.currentUrl = url; // Улучшенный PowerShell скрипт с контролем громкости const script = ` # Включаем отображение ошибок $ErrorActionPreference = "Continue" # Создаем Windows Media Player Add-Type -AssemblyName presentationCore $player = New-Object System.Windows.Media.MediaPlayer # Выводим PID для контроля громкости Write-Host "PID:$PID" # Открываем поток try { $player.Open([System.Uri]"${url}") $player.Volume = ${this.volume / 100} # Ждем загрузки потока Start-Sleep -Seconds 2 # Начинаем воспроизведение $player.Play() Write-Host "STATUS:PLAYING" # Держим процесс активным и проверяем громкость while ($true) { # Проверяем файл с командами громкости $cmdFile = "$env:TEMP\\radio_volume_$PID.txt" if (Test-Path $cmdFile) { $newVolume = Get-Content $cmdFile -ErrorAction SilentlyContinue if ($newVolume) { $player.Volume = [double]$newVolume / 100 Write-Host "VOLUME:$newVolume" Remove-Item $cmdFile -Force -ErrorAction SilentlyContinue } } Start-Sleep -Milliseconds 500 } } catch { Write-Host "ERROR:$($_.Exception.Message)" }`; // Сохраняем скрипт const scriptPath = path.join(__dirname, 'temp_radio.ps1'); fs.writeFileSync(scriptPath, script); // Запускаем PowerShell с более чистыми параметрами this.radioProcess = spawn('powershell', [ '-ExecutionPolicy', 'Bypass', '-NoProfile', '-WindowStyle', 'Hidden', '-File', scriptPath ], { windowsHide: true }); this.radioProcess.stdout.on('data', (data) => { const output = data.toString().trim(); console.log('[RADIO] Вывод:', output); // Извлекаем PID const pidMatch = output.match(/PID:(\d+)/); if (pidMatch) { this.playerPid = pidMatch[1]; console.log('[RADIO] PID процесса:', this.playerPid); // Применяем громкость через NirCmd если доступен this._applyNircmdVolume(); } // Проверяем статус if (output.includes('STATUS:PLAYING')) { console.log('[RADIO] ✅ Радио запущено успешно'); } }); this.radioProcess.stderr.on('data', (data) => { console.error('[RADIO] Ошибка:', data.toString()); }); this.radioProcess.on('exit', (code) => { console.log('[RADIO] Процесс завершен с кодом:', code); this.isPlaying = false; this._cleanup(); }); this.isPlaying = true; // Запускаем периодическое применение громкости this._startVolumeControl(); } stop() { if (this.radioProcess) { console.log('[RADIO] ⏹️ Остановка радио'); // Останавливаем контроль громкости if (this.volumeControlInterval) { clearInterval(this.volumeControlInterval); this.volumeControlInterval = null; } this.radioProcess.kill(); this.radioProcess = null; } this._cleanup(); this.isPlaying = false; this.currentUrl = null; this.playerPid = null; } setVolume(volume) { this.volume = Math.max(0, Math.min(100, volume)); console.log('[RADIO] 🔊 Установка громкости:', this.volume); if (this.isPlaying) { // Метод 1: Через NirCmd (самый надежный) this._applyNircmdVolume(); // Метод 2: Через файл команд для PowerShell if (this.playerPid) { const cmdFile = path.join(process.env.TEMP || '', `radio_volume_${this.playerPid}.txt`); fs.writeFileSync(cmdFile, this.volume.toString()); } } } _applyNircmdVolume() { const nircmdPath = path.join(__dirname, 'tools', 'nircmd.exe'); if (fs.existsSync(nircmdPath)) { if (this.playerPid) { // Метод 1: Устанавливаем громкость для конкретного PID spawn(nircmdPath, [ 'setappvolume', `/${this.playerPid}`, (this.volume / 100).toString() ], { stdio: 'ignore', windowsHide: true }); // Метод 2: Дополнительно для всех PowerShell процессов spawn(nircmdPath, [ 'setappvolume', 'powershell.exe', (this.volume / 100).toString() ], { stdio: 'ignore', windowsHide: true }); console.log('[RADIO] ✅ Громкость установлена через NirCmd'); } } else { console.log('[RADIO] ⚠️ NirCmd не найден! Установите его для управления громкостью.'); console.log('[RADIO] 📁 Путь для установки:', nircmdPath); } } _startVolumeControl() { // Применяем громкость каждые 2 секунды для надежности this.volumeControlInterval = setInterval(() => { if (this.isPlaying && this.playerPid) { this._applyNircmdVolume(); } }, 2000); } _cleanup() { // Удаляем временные файлы try { const scriptPath = path.join(__dirname, 'temp_radio.ps1'); if (fs.existsSync(scriptPath)) { fs.unlinkSync(scriptPath); } // Удаляем файл команд громкости if (this.playerPid) { const cmdFile = path.join(process.env.TEMP || '', `radio_volume_${this.playerPid}.txt`); if (fs.existsSync(cmdFile)) { fs.unlinkSync(cmdFile); } } } catch (e) { // Игнорируем ошибки очистки } } } module.exports = ImprovedRadioPlayer;