// Windows Audio Player с управлением через stdin const { spawn } = require('child_process'); const fs = require('fs'); const path = require('path'); class WindowsStdinAudio { constructor() { this.currentProcess = null; this.currentFile = null; this.isPlaying = false; this.volume = 70; this.playerReady = false; } play(filePath, startPosition = 0) { this.stop(); if (!fs.existsSync(filePath)) { console.error('[STDIN-AUDIO] Файл не найден:', filePath); return this; } this.currentFile = filePath; const volumeValue = this.volume / 100; console.log('[STDIN-AUDIO] Запуск воспроизведения:', path.basename(filePath)); console.log('[STDIN-AUDIO] Начальная громкость:', this.volume + '%'); // PowerShell скрипт с чтением команд из stdin const script = ` Add-Type -AssemblyName presentationcore $player = New-Object System.Windows.Media.MediaPlayer $player.Volume = ${volumeValue} $player.Open("${filePath.replace(/\\/g, '\\\\')}") # Ждем загрузки $timeout = 0 while ($player.NaturalDuration.HasTimeSpan -eq $false -and $timeout -lt 50) { Start-Sleep -Milliseconds 100 $timeout++ } if ($player.NaturalDuration.HasTimeSpan -eq $false) { Write-Host "ERROR:Failed to load" exit 1 } # Запускаем воспроизведение $player.Play() Write-Host "PLAYING" Write-Host "VOLUME:$([int]($player.Volume * 100))" # Создаем поток для чтения stdin $reader = [System.IO.StreamReader]::new([Console]::OpenStandardInput()) $task = $null # Главный цикл while ($true) { # Неблокирующее чтение stdin if ($reader.Peek() -ge 0) { $line = $reader.ReadLine() if ($line -match "^VOLUME:(\d+)$") { $newVolume = [int]$matches[1] / 100 $player.Volume = $newVolume Write-Host "VOLUME_CHANGED:$($matches[1])" } elseif ($line -eq "STOP") { break } } # Проверяем завершение if ($player.Position -ge $player.NaturalDuration.TimeSpan) { Write-Host "FINISHED" break } Start-Sleep -Milliseconds 50 } $player.Stop() $player.Close() `; this.currentProcess = spawn('powershell', [ '-NoProfile', '-Command', script ], { windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] // stdin, stdout, stderr }); this.isPlaying = true; // Обработка вывода this.currentProcess.stdout.on('data', (data) => { const output = data.toString().trim(); if (output) { console.log('[STDIN-AUDIO]', output); if (output === 'PLAYING') { this.playerReady = true; } } }); this.currentProcess.stderr.on('data', (data) => { console.error('[STDIN-AUDIO] Ошибка:', data.toString()); }); this.currentProcess.on('close', (code) => { console.log('[STDIN-AUDIO] Процесс завершен:', code); this.isPlaying = false; this.currentProcess = null; this.playerReady = false; }); return this; } stop() { if (this.currentProcess) { console.log('[STDIN-AUDIO] Остановка'); try { // Отправляем команду через stdin this.currentProcess.stdin.write('STOP\n'); setTimeout(() => { if (this.currentProcess) { this.currentProcess.kill(); } }, 100); } catch (e) { this.currentProcess.kill(); } this.currentProcess = null; } this.isPlaying = false; this.playerReady = false; return this; } setVolume(volume) { this.volume = Math.max(0, Math.min(100, volume)); console.log('[STDIN-AUDIO] Установка громкости:', this.volume); if (this.isPlaying && this.currentProcess && this.currentProcess.stdin) { try { this.currentProcess.stdin.write(`VOLUME:${this.volume}\n`); console.log('[STDIN-AUDIO] Команда громкости отправлена через stdin'); } catch (e) { console.error('[STDIN-AUDIO] Ошибка отправки команды:', e.message); } } return this; } } // Экспортируем как WindowsAudioPlayer для совместимости module.exports = { WindowsAudioPlayer: WindowsStdinAudio };