- Клиентская часть Vue 3 + Vite - Серверная часть Node.js + WebSocket - Система авторизации и смен - Управление игровыми портами - Поддержка тем (светлая/темная) - Адаптивный дизайн 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
218 lines
7.7 KiB
JavaScript
218 lines
7.7 KiB
JavaScript
// Улучшенный радио плеер с точным управлением громкостью процесса
|
||
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; |