// Простой радио плеер для Windows используя PowerShell и Windows Media Player const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); class SimpleRadioPlayer { constructor() { this.radioProcess = null; this.isPlaying = false; this.volume = 70; this.currentUrl = null; this.playerPid = null; } play(url) { this.stop(); // Добавляем протокол если его нет if (!url.startsWith('http://') && !url.startsWith('https://')) { url = 'http://' + url; } console.log('[RADIO] 📻 Запуск радио:', url); this.currentUrl = url; // PowerShell скрипт для воспроизведения через Windows Media Player const script = ` Add-Type -AssemblyName presentationCore $player = New-Object System.Windows.Media.MediaPlayer $player.Open([System.Uri]"${url}") $player.Volume = ${this.volume / 100} $player.Play() # Выводим PID процесса Write-Host "PID:$PID" # Держим процесс активным и слушаем команды while ($true) { Start-Sleep -Seconds 1 }`; // Сохраняем скрипт во временный файл const scriptPath = path.join(__dirname, 'temp_radio.ps1'); fs.writeFileSync(scriptPath, script); // Запускаем PowerShell this.radioProcess = spawn('powershell', [ '-ExecutionPolicy', 'Bypass', '-File', scriptPath ]); this.radioProcess.stdout.on('data', (data) => { const output = data.toString(); console.log('[RADIO] Вывод:', output); // Извлекаем PID const pidMatch = output.match(/PID:(\d+)/); if (pidMatch) { this.playerPid = pidMatch[1]; console.log('[RADIO] PID процесса:', this.playerPid); } }); this.radioProcess.stderr.on('data', (data) => { console.error('[RADIO] Ошибка:', data.toString()); }); this.radioProcess.on('exit', (code) => { console.log('[RADIO] Процесс завершен с кодом:', code); this.isPlaying = false; // Удаляем временный файл try { fs.unlinkSync(scriptPath); } catch (e) {} }); this.isPlaying = true; } stop() { if (this.radioProcess) { console.log('[RADIO] ⏹️ Остановка радио'); this.radioProcess.kill(); this.radioProcess = null; } 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); // Пробуем установить громкость конкретного процесса через nircmd const nircmdPath = path.join(__dirname, 'tools', 'nircmd.exe'); if (fs.existsSync(nircmdPath)) { if (this.playerPid) { // Устанавливаем громкость для конкретного PID spawn(nircmdPath, ['setappvolume', `/${this.playerPid}`, (this.volume / 100).toString()], { stdio: 'ignore', windowsHide: true }); console.log('[RADIO] ✅ Громкость процесса установлена через nircmd для PID:', this.playerPid); } else { // Пробуем установить для всех процессов PowerShell spawn(nircmdPath, ['setappvolume', 'powershell.exe', (this.volume / 100).toString()], { stdio: 'ignore', windowsHide: true }); console.log('[RADIO] ✅ Громкость установлена для всех процессов PowerShell'); } return; } // Если nircmd нет, используем VBScript для изменения громкости MediaPlayer if (this.isPlaying && this.currentUrl) { console.log('[RADIO] 🔄 Перезапускаем с новой громкостью...'); const url = this.currentUrl; this.stop(); setTimeout(() => this.play(url), 500); return; } // Фолбэк - системная громкость через PowerShell console.log('[RADIO] ⚠️ Устанавливаем системную громкость (nircmd не найден)'); const volumeScript = ` Add-Type -TypeDefinition @' using System.Runtime.InteropServices; [Guid("5CDF2C82-841E-4546-9722-0CF74078229A"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IAudioEndpointVolume { int f(); int g(); int h(); int i(); int SetMasterVolumeLevelScalar(float fLevel, System.Guid pguidEventContext); int j(); int GetMasterVolumeLevelScalar(out float pfLevel); int k(); int l(); int m(); int n(); int SetMute([MarshalAs(UnmanagedType.Bool)] bool bMute, System.Guid pguidEventContext); int GetMute(out bool pbMute); } [Guid("D666063F-1587-4E43-81F1-B948E807363F"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IMMDevice { int Activate(ref System.Guid id, int clsCtx, int activationParams, out IAudioEndpointVolume aev); } [Guid("A95664D2-9614-4F35-A746-DE8DB63617E6"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] interface IMMDeviceEnumerator { int f(); int GetDefaultAudioEndpoint(int dataFlow, int role, out IMMDevice endpoint); } [ComImport, Guid("BCDE0395-E52F-467C-8E3D-C4579291692E")] class MMDeviceEnumeratorComObject { } public class Audio { static IAudioEndpointVolume Vol() { var enumerator = new MMDeviceEnumeratorComObject() as IMMDeviceEnumerator; IMMDevice dev = null; Marshal.ThrowExceptionForHR(enumerator.GetDefaultAudioEndpoint(0, 1, out dev)); IAudioEndpointVolume epv = null; var epvid = typeof(IAudioEndpointVolume).GUID; Marshal.ThrowExceptionForHR(dev.Activate(ref epvid, 23, 0, out epv)); return epv; } public static void SetVolume(float level) { Marshal.ThrowExceptionForHR(Vol().SetMasterVolumeLevelScalar(level, System.Guid.Empty)); } } '@ [Audio]::SetVolume(${this.volume / 100})`; spawn('powershell', ['-Command', volumeScript], { stdio: 'ignore' }); } } module.exports = SimpleRadioPlayer;