Files
vue-pult/server/windows-audio-player.backup.js
sasha 3e90269b0b Initial commit: Vue.js тир управления система
- Клиентская часть Vue 3 + Vite
- Серверная часть Node.js + WebSocket
- Система авторизации и смен
- Управление игровыми портами
- Поддержка тем (светлая/темная)
- Адаптивный дизайн

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-19 12:24:22 +03:00

419 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Windows-специфичный аудио плеер с поддержкой изменения громкости в реальном времени
const { spawn, exec } = require('child_process');
const fs = require('fs');
const path = require('path');
const net = require('net');
class WindowsAudioPlayer {
constructor() {
this.currentProcess = null;
this.currentFile = null;
this.isPlaying = false;
this.isPaused = false;
this.volume = 70;
this.position = 0;
this.server = null;
this.client = null;
this.playerReady = false;
console.log('[WINDOWS-AUDIO] Инициализирован Windows аудио плеер');
}
play(filePath, startPosition = 0) {
this.stop();
if (!fs.existsSync(filePath)) {
console.error('[WINDOWS-AUDIO] Файл не найден:', filePath);
return this;
}
this.currentFile = filePath;
this.position = startPosition;
// Создаем PowerShell скрипт с поддержкой управления громкостью
const volumeValue = this.volume / 100;
console.log('[WINDOWS-AUDIO] Установка громкости MediaPlayer:', volumeValue, '(', this.volume, '%)');
const script = `
Add-Type -AssemblyName presentationcore
$player = New-Object System.Windows.Media.MediaPlayer
$player.Volume = ${volumeValue}
$player.Open("${filePath}")
Write-Host "LOADING_FILE:${filePath}"
# Ждем загрузки
$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 file"
exit 1
}
# Устанавливаем позицию если нужно
if (${startPosition} -gt 0) {
$player.Position = [TimeSpan]::FromSeconds(${startPosition})
}
# Запускаем воспроизведение
$player.Play()
Write-Host "PLAYING"
# Главный цикл с проверкой команд
$commandFile = "$env:TEMP\\audio_player_$PID.cmd"
$volumeFile = "$env:TEMP\\audio_player_$PID.vol"
while ($true) {
# Проверяем команду
if (Test-Path $commandFile) {
$command = Get-Content $commandFile
Remove-Item $commandFile -Force
switch ($command) {
"STOP" {
$player.Stop()
$player.Close()
exit
}
"PAUSE" {
$player.Pause()
}
"RESUME" {
$player.Play()
}
}
}
# Проверяем изменение громкости
if (Test-Path $volumeFile) {
$newVolume = Get-Content $volumeFile
Remove-Item $volumeFile -Force
$volumeValue = [double]$newVolume / 100
$player.Volume = $volumeValue
Write-Host "VOLUME_CHANGED:$newVolume"
Write-Host "PLAYER_VOLUME:$($player.Volume)"
}
# Проверяем завершение воспроизведения
if ($player.NaturalDuration.HasTimeSpan -and $player.Position -ge $player.NaturalDuration.TimeSpan) {
Write-Host "FINISHED"
break
}
Start-Sleep -Milliseconds 50
}
$player.Close()`;
console.log('[WINDOWS-AUDIO] Запускаем воспроизведение:', filePath);
this.currentProcess = spawn('powershell', [
'-WindowStyle', 'Hidden',
'-Command', script
], {
windowsHide: true
});
this.isPlaying = true;
this.isPaused = false;
// Сохраняем PID процесса для использования в setVolume
console.log('[WINDOWS-AUDIO] Процесс запущен с PID:', this.currentProcess.pid);
// Обработка вывода
this.currentProcess.stdout.on('data', (data) => {
const output = data.toString().trim();
console.log('[WINDOWS-AUDIO] Вывод:', output);
if (output === 'PLAYING') {
this.playerReady = true;
} else if (output === 'FINISHED') {
this.isPlaying = false;
} else if (output.startsWith('VOLUME_CHANGED:')) {
console.log('[WINDOWS-AUDIO] ✅ Громкость успешно изменена:', output);
} else if (output.startsWith('PLAYER_VOLUME:')) {
console.log('[WINDOWS-AUDIO] 🔊 Текущая громкость плеера:', output);
} else if (output.startsWith('WATCHING_FILES:')) {
// Логирование файлов для отладки
} else if (output.startsWith('ALIVE:')) {
// Периодическая проверка состояния
} else if (output.startsWith('VOLUME_SET:')) {
console.log('[WINDOWS-AUDIO] Установлена громкость MediaPlayer:', output);
} else if (output.startsWith('ERROR:')) {
console.error('[WINDOWS-AUDIO] ОШИБКА:', output);
this.isPlaying = false;
} else if (output.startsWith('STATUS:')) {
console.log('[WINDOWS-AUDIO] Статус воспроизведения:', output);
} else if (output.startsWith('LOADING_FILE:')) {
console.log('[WINDOWS-AUDIO] Загрузка файла:', output);
} else if (output.startsWith('FILE_LOADED:')) {
console.log('[WINDOWS-AUDIO] Файл загружен:', output);
}
});
// Обработка ошибок
this.currentProcess.stderr.on('data', (data) => {
console.error('[WINDOWS-AUDIO] Ошибка PowerShell:', data.toString());
});
this.currentProcess.on('close', (code) => {
console.log('[WINDOWS-AUDIO] Процесс завершен:', code);
this.isPlaying = false;
this.isPaused = false;
this.currentProcess = null;
this.playerReady = false;
this._cleanupTempFiles();
});
this.currentProcess.on('error', (err) => {
console.error('[WINDOWS-AUDIO] Ошибка процесса:', err.message);
this.isPlaying = false;
this.currentProcess = null;
this._cleanupTempFiles();
});
return this;
}
stop() {
if (this.currentProcess) {
console.log('[WINDOWS-AUDIO] Остановка процесса PID:', this.currentProcess.pid);
// Сразу убиваем процесс PowerShell
try {
process.kill(this.currentProcess.pid, 'SIGTERM');
} catch (e) {
console.log('[WINDOWS-AUDIO] Не удалось остановить через SIGTERM, используем taskkill');
try {
spawn('taskkill', ['/F', '/T', '/PID', this.currentProcess.pid.toString()], {
stdio: 'ignore',
windowsHide: true
});
} catch (e2) {
console.error('[WINDOWS-AUDIO] Ошибка при остановке процесса:', e2);
}
}
this.currentProcess = null;
}
this.isPlaying = false;
this.isPaused = false;
this.playerReady = false;
this._cleanupTempFiles();
return this;
}
pause() {
if (!this.isPlaying || this.isPaused || !this.currentProcess) return this;
console.log('[WINDOWS-AUDIO] Пауза не поддерживается, останавливаем воспроизведение');
// PowerShell MediaPlayer не поддерживает паузу надёжно, поэтому останавливаем
this.stop();
return this;
}
resume() {
console.log('[WINDOWS-AUDIO] Возобновление не поддерживается');
return this;
}
setVolume(volume) {
this.volume = Math.max(0, Math.min(100, volume));
console.log('[WINDOWS-AUDIO] Установка громкости:', this.volume);
// Если играет, применяем громкость в реальном времени
if (this.isPlaying && this.currentProcess) {
const volumeFile = `${process.env.TEMP}\\audio_player_${this.currentProcess.pid}.vol`;
try {
fs.writeFileSync(volumeFile, this.volume.toString());
console.log('[WINDOWS-AUDIO] Команда изменения громкости отправлена в файл:', volumeFile);
} catch (e) {
console.error('[WINDOWS-AUDIO] Ошибка при изменении громкости:', e.message);
// НЕ меняем системную громкость - это влияет на всё
console.log('[WINDOWS-AUDIO] Громкость будет применена при следующем воспроизведении');
}
}
return this;
}
_setSystemVolume() {
const volumePercent = this.volume / 100;
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);
}
[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(${volumePercent})`;
exec(`powershell -WindowStyle Hidden -Command "${volumeScript}"`, (err) => {
if (!err) {
console.log('[WINDOWS-AUDIO] Системная громкость установлена:', this.volume + '%');
}
});
}
_cleanupTempFiles() {
// Очищаем временные файлы
const tempDir = process.env.TEMP;
if (tempDir) {
fs.readdir(tempDir, (err, files) => {
if (!err) {
files.forEach(file => {
if (file.startsWith('audio_player_') && (file.endsWith('.cmd') || file.endsWith('.vol'))) {
fs.unlink(path.join(tempDir, file), () => {});
}
});
}
});
}
}
getPosition() {
if (!this.isPlaying) return 0;
// Примерная позиция - для точной нужно было бы запрашивать у плеера
return this.position;
}
}
// Радио плеер для Windows
class WindowsRadioPlayer extends WindowsAudioPlayer {
playStream(url) {
this.stop();
console.log('[WINDOWS-RADIO] Воспроизведение потока:', url);
const volumeValue = Math.max(0.2, this.volume / 100);
console.log('[WINDOWS-RADIO] Установка громкости MediaPlayer:', volumeValue, '(', this.volume, '%)');
const script = `
Add-Type -AssemblyName presentationcore
$player = New-Object System.Windows.Media.MediaPlayer
$player.Volume = ${volumeValue}
$player.Open("${url}")
Write-Host "LOADING_RADIO:${url}"
# Ждем буферизации
Start-Sleep -Seconds 2
$player.Play()
Write-Host "PLAYING"
# Главный цикл с проверкой команд
$commandFile = "$env:TEMP\\audio_player_$PID.cmd"
$volumeFile = "$env:TEMP\\audio_player_$PID.vol"
while ($true) {
# Проверяем команду
if (Test-Path $commandFile) {
$command = Get-Content $commandFile
Remove-Item $commandFile -Force
if ($command -eq "STOP") {
$player.Stop()
$player.Close()
exit
}
}
# Проверяем изменение громкости
if (Test-Path $volumeFile) {
$newVolume = Get-Content $volumeFile
Remove-Item $volumeFile -Force
$volumeValue = [double]$newVolume / 100
$player.Volume = $volumeValue
Write-Host "VOLUME_CHANGED:$newVolume"
Write-Host "PLAYER_VOLUME:$($player.Volume)"
}
Start-Sleep -Milliseconds 50
}`;
this.currentProcess = spawn('powershell', [
'-WindowStyle', 'Hidden',
'-Command', script
], {
windowsHide: true
});
this.isPlaying = true;
this.isPaused = false;
// Обработка вывода
this.currentProcess.stdout.on('data', (data) => {
const output = data.toString().trim();
console.log('[WINDOWS-RADIO] Вывод:', output);
if (output === 'PLAYING') {
this.playerReady = true;
} else if (output.startsWith('VOLUME:')) {
console.log('[WINDOWS-RADIO] Громкость изменена:', output);
} else if (output.startsWith('LOADING_RADIO:')) {
console.log('[WINDOWS-RADIO] Загрузка радио:', output);
} else if (output.startsWith('ERROR:')) {
console.error('[WINDOWS-RADIO] ОШИБКА:', output);
this.isPlaying = false;
}
});
// Обработка ошибок
this.currentProcess.stderr.on('data', (data) => {
console.error('[WINDOWS-RADIO] Ошибка PowerShell:', data.toString());
});
this.currentProcess.on('close', (code) => {
console.log('[WINDOWS-RADIO] Процесс завершен:', code);
this.isPlaying = false;
this.currentProcess = null;
this.playerReady = false;
this._cleanupTempFiles();
});
this.currentProcess.on('error', (err) => {
console.error('[WINDOWS-RADIO] Ошибка процесса:', err.message);
this.isPlaying = false;
this.currentProcess = null;
this._cleanupTempFiles();
});
return this;
}
}
module.exports = { WindowsAudioPlayer, WindowsRadioPlayer };