Files
Painobar-helper/ProfileManager.cs
T
2026-08-11 22:42:01 -04:00

300 lines
11 KiB
C#

using System.Text;
using System.Text.Json;
namespace PainoBar_Helper
{
/// <summary>
/// Manages Pianobar profiles including creation, deletion, and configuration file generation
/// </summary>
public class ProfileManager
{
private const string ProfilesFileName = "profiles.json";
private readonly string _profilesFilePath;
private List<Profile> _profiles;
private string? _activeProfileName;
public ProfileManager()
{
string appDataPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"PianobarHelper"
);
Directory.CreateDirectory(appDataPath);
_profilesFilePath = Path.Combine(appDataPath, ProfilesFileName);
_profiles = new List<Profile>();
LoadProfiles();
}
public event EventHandler? ProfilesChanged;
public event EventHandler? ActiveProfileChanged;
public IReadOnlyList<Profile> Profiles => _profiles.AsReadOnly();
public string? ActiveProfileName => _activeProfileName;
public Profile? GetActiveProfile()
{
if (string.IsNullOrEmpty(_activeProfileName))
return null;
return _profiles.FirstOrDefault(p => p.Name == _activeProfileName);
}
public void SetActiveProfile(string profileName)
{
var profile = _profiles.FirstOrDefault(p => p.Name == profileName);
if (profile == null)
throw new ArgumentException($"Profile '{profileName}' does not exist.");
_activeProfileName = profileName;
SaveProfiles(); // Save immediately to persist the active profile
ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
}
public void CreateProfile(string name, ProfileSettings settings)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Profile name cannot be empty.");
if (_profiles.Any(p => p.Name.Equals(name, StringComparison.OrdinalIgnoreCase)))
throw new InvalidOperationException($"Profile '{name}' already exists.");
var profile = new Profile
{
Name = name,
Settings = settings
};
_profiles.Add(profile);
if (_profiles.Count == 1)
_activeProfileName = name;
SaveProfiles();
ProfilesChanged?.Invoke(this, EventArgs.Empty);
if (settings.OverrideCredentials && !string.IsNullOrEmpty(settings.ConfigFilePath))
GenerateConfigFile(profile);
}
public void UpdateProfile(string name, ProfileSettings settings)
{
var profile = _profiles.FirstOrDefault(p => p.Name == name);
if (profile == null)
throw new ArgumentException($"Profile '{name}' does not exist.");
profile.Settings = settings;
SaveProfiles();
ProfilesChanged?.Invoke(this, EventArgs.Empty);
if (settings.OverrideCredentials && !string.IsNullOrEmpty(settings.ConfigFilePath))
GenerateConfigFile(profile);
}
public void DeleteProfile(string name)
{
var profile = _profiles.FirstOrDefault(p => p.Name == name);
if (profile == null)
return;
_profiles.Remove(profile);
if (_activeProfileName == name)
{
_activeProfileName = _profiles.FirstOrDefault()?.Name;
ActiveProfileChanged?.Invoke(this, EventArgs.Empty);
}
SaveProfiles();
ProfilesChanged?.Invoke(this, EventArgs.Empty);
}
private void LoadProfiles()
{
if (!File.Exists(_profilesFilePath))
{
_profiles = new List<Profile>();
return;
}
try
{
string json = File.ReadAllText(_profilesFilePath);
var data = JsonSerializer.Deserialize<ProfileData>(json);
if (data != null)
{
_profiles = data.Profiles ?? new List<Profile>();
_activeProfileName = data.ActiveProfile;
}
}
catch
{
_profiles = new List<Profile>();
}
}
private void SaveProfiles()
{
var data = new ProfileData
{
Profiles = _profiles,
ActiveProfile = _activeProfileName
};
string json = JsonSerializer.Serialize(data, new JsonSerializerOptions { WriteIndented = true });
File.WriteAllText(_profilesFilePath, json);
}
private void GenerateConfigFile(Profile profile)
{
var settings = profile.Settings;
if (string.IsNullOrEmpty(settings.ConfigFilePath))
return;
try
{
var configDir = Path.GetDirectoryName(settings.ConfigFilePath);
if (!string.IsNullOrEmpty(configDir))
Directory.CreateDirectory(configDir);
// Generate event command script path
var eventCmdPath = Path.Combine(configDir, "eventcmd.cmd");
GenerateEventCommandScript(eventCmdPath, profile);
var sb = new StringBuilder();
sb.AppendLine("# Pianobar configuration file");
sb.AppendLine($"# Generated by Pianobar Helper for profile: {profile.Name}");
sb.AppendLine();
if (settings.OverrideCredentials)
{
if (!string.IsNullOrEmpty(settings.PianobarUser))
sb.AppendLine($"user = {settings.PianobarUser}");
if (!string.IsNullOrEmpty(settings.PianobarPassword))
sb.AppendLine($"password = {settings.PianobarPassword}");
sb.AppendLine();
}
// Add event command directive
sb.AppendLine($"event_command = \"{eventCmdPath}\"");
sb.AppendLine();
// Additional settings for better integration
sb.AppendLine("# Output formatting");
sb.AppendLine("format_nowplaying_song = %t|%a|%l|%r");
sb.AppendLine("format_station_list = %i) %n");
sb.AppendLine();
File.WriteAllText(settings.ConfigFilePath, sb.ToString());
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to generate config file: {ex.Message}", ex);
}
}
private void GenerateEventCommandScript(string scriptPath, Profile profile)
{
try
{
// Create the directory for the event output file
var appDataPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"PianobarHelper"
);
Directory.CreateDirectory(appDataPath);
var eventOutputPath = Path.Combine(appDataPath, $"events_{profile.Name}.json");
// Generate Windows batch script for event handling
var sb = new StringBuilder();
sb.AppendLine("@echo off");
sb.AppendLine("REM Pianobar event command script");
sb.AppendLine("REM Generated by Pianobar Helper");
sb.AppendLine();
sb.AppendLine($"set \"EVENT_OUTPUT={eventOutputPath}\"");
sb.AppendLine();
sb.AppendLine("REM Create JSON output for the event");
sb.AppendLine("(");
sb.AppendLine(" echo {");
sb.AppendLine(" echo \"event\": \"%1\",");
sb.AppendLine(" echo \"timestamp\": \"%date% %time%\",");
sb.AppendLine(" echo \"artist\": \"%artist%\",");
sb.AppendLine(" echo \"title\": \"%title%\",");
sb.AppendLine(" echo \"album\": \"%album%\",");
sb.AppendLine(" echo \"coverArt\": \"%coverArt%\",");
sb.AppendLine(" echo \"stationName\": \"%stationName%\",");
sb.AppendLine(" echo \"songDuration\": \"%songDuration%\",");
sb.AppendLine(" echo \"songPlayed\": \"%songPlayed%\",");
sb.AppendLine(" echo \"rating\": \"%rating%\",");
sb.AppendLine(" echo \"detailUrl\": \"%detailUrl%\"");
sb.AppendLine(" echo }");
sb.AppendLine(") > \"%EVENT_OUTPUT%\"");
sb.AppendLine();
sb.AppendLine("exit /b 0");
File.WriteAllText(scriptPath, sb.ToString());
}
catch (Exception ex)
{
throw new InvalidOperationException($"Failed to generate event command script: {ex.Message}", ex);
}
}
public string? GetActiveConfigPath()
{
var activeProfile = GetActiveProfile();
if (activeProfile?.Settings.OverrideCredentials == true)
return activeProfile.Settings.ConfigFilePath;
return null;
}
public string? GetEventOutputPath()
{
var activeProfile = GetActiveProfile();
if (activeProfile == null)
return null;
var appDataPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
"PianobarHelper"
);
return Path.Combine(appDataPath, $"events_{activeProfile.Name}.json");
}
}
public class Profile
{
public string Name { get; set; } = string.Empty;
public ProfileSettings Settings { get; set; } = new ProfileSettings();
}
public class ProfileSettings
{
// Pianobar Path
public string PianobarPath { get; set; } = "pianobar.exe";
// Output Settings
public bool EnableTextFile { get; set; }
public string TextFilePath { get; set; } = string.Empty;
public bool EnableWebServer { get; set; }
public int WebServerPort { get; set; } = 8080;
public bool EnableToastNotifications { get; set; }
public bool EnableSMTC { get; set; }
// Pianobar Config & Auth
public bool OverrideCredentials { get; set; }
public string ConfigFilePath { get; set; } = string.Empty;
public string PianobarUser { get; set; } = string.Empty;
public string PianobarPassword { get; set; } = string.Empty;
// Process Management
public bool KillProcessOnDisconnect { get; set; }
}
internal class ProfileData
{
public List<Profile>? Profiles { get; set; }
public string? ActiveProfile { get; set; }
}
}