UI is now updated through MPD events and not every second + misc fixes
This commit is contained in:
parent
1b44c64ec5
commit
72d2c5993d
@ -14,15 +14,15 @@ namespace unison
|
|||||||
{
|
{
|
||||||
base.OnStartup(e);
|
base.OnStartup(e);
|
||||||
|
|
||||||
Snapcast = new SnapcastHandler();
|
|
||||||
Current.Properties["snapcast"] = Snapcast;
|
|
||||||
|
|
||||||
MPD = new MPDHandler();
|
MPD = new MPDHandler();
|
||||||
Current.Properties["mpd"] = MPD;
|
Current.Properties["mpd"] = MPD;
|
||||||
|
|
||||||
Hotkeys = new HotkeyHandler();
|
Hotkeys = new HotkeyHandler();
|
||||||
Current.Properties["hotkeys"] = Hotkeys;
|
Current.Properties["hotkeys"] = Hotkeys;
|
||||||
|
|
||||||
|
Snapcast = new SnapcastHandler();
|
||||||
|
Current.Properties["snapcast"] = Snapcast;
|
||||||
|
|
||||||
Current.MainWindow = new MainWindow();
|
Current.MainWindow = new MainWindow();
|
||||||
|
|
||||||
Systray = (TaskbarIcon)FindResource("SystrayTaskbar");
|
Systray = (TaskbarIcon)FindResource("SystrayTaskbar");
|
||||||
|
@ -6,12 +6,16 @@ using System.Net;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Threading;
|
||||||
using MpcNET;
|
using MpcNET;
|
||||||
using MpcNET.Commands.Database;
|
using MpcNET.Commands.Database;
|
||||||
using MpcNET.Commands.Playback;
|
using MpcNET.Commands.Playback;
|
||||||
using MpcNET.Commands.Reflection;
|
using MpcNET.Commands.Reflection;
|
||||||
using MpcNET.Commands.Status;
|
using MpcNET.Commands.Status;
|
||||||
|
using MpcNET.Message;
|
||||||
|
using MpcNET.Types;
|
||||||
|
|
||||||
namespace unison
|
namespace unison
|
||||||
{
|
{
|
||||||
@ -26,13 +30,17 @@ namespace unison
|
|||||||
public bool _currentConsume;
|
public bool _currentConsume;
|
||||||
public double _currentTime;
|
public double _currentTime;
|
||||||
public double _totalTime;
|
public double _totalTime;
|
||||||
|
|
||||||
BitmapFrame _cover;
|
BitmapFrame _cover;
|
||||||
|
|
||||||
|
public event EventHandler ConnectionChanged;
|
||||||
|
public event EventHandler StatusChanged;
|
||||||
|
public event EventHandler SongChanged;
|
||||||
|
public event EventHandler CoverChanged;
|
||||||
|
|
||||||
public static MpdStatus BOGUS_STATUS = new MpdStatus(0, false, false, false, false, -1, -1, -1, MpdState.Unknown, -1, -1, -1, -1, TimeSpan.Zero, TimeSpan.Zero, -1, -1, -1, -1, -1, "", "");
|
public static MpdStatus BOGUS_STATUS = new MpdStatus(0, false, false, false, false, -1, -1, -1, MpdState.Unknown, -1, -1, -1, -1, TimeSpan.Zero, TimeSpan.Zero, -1, -1, -1, -1, -1, "", "");
|
||||||
public MpdStatus CurrentStatus { get; private set; } = BOGUS_STATUS;
|
public MpdStatus CurrentStatus { get; private set; } = BOGUS_STATUS;
|
||||||
|
|
||||||
MpcNET.Types.IMpdFile CurrentSong { get; set; }
|
IMpdFile CurrentSong { get; set; }
|
||||||
|
|
||||||
private readonly System.Timers.Timer _elapsedTimer;
|
private readonly System.Timers.Timer _elapsedTimer;
|
||||||
private async void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e)
|
private async void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e)
|
||||||
@ -49,7 +57,6 @@ namespace unison
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MpcConnection _connection;
|
private MpcConnection _connection;
|
||||||
|
|
||||||
private MpcConnection _commandConnection;
|
private MpcConnection _commandConnection;
|
||||||
|
|
||||||
private IPEndPoint _mpdEndpoint;
|
private IPEndPoint _mpdEndpoint;
|
||||||
@ -64,20 +71,76 @@ namespace unison
|
|||||||
|
|
||||||
_elapsedTimer = new System.Timers.Timer(500);
|
_elapsedTimer = new System.Timers.Timer(500);
|
||||||
_elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer);
|
_elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer);
|
||||||
|
|
||||||
|
ConnectionChanged += OnConnectionChanged;
|
||||||
|
StatusChanged += OnStatusChanged;
|
||||||
|
SongChanged += OnSongChanged;
|
||||||
|
CoverChanged += OnCoverChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Initialize()
|
static void OnConnectionChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||||
|
MainWin.OnConnectionChanged(sender, e);
|
||||||
|
|
||||||
|
SnapcastHandler Snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||||
|
Snapcast.OnConnectionChanged(sender, e);
|
||||||
|
|
||||||
|
}, DispatcherPriority.ContextIdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnStatusChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||||
|
MainWin.OnStatusChanged(sender, e);
|
||||||
|
}, DispatcherPriority.ContextIdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnSongChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||||
|
MainWin.OnSongChanged(sender, e);
|
||||||
|
}, DispatcherPriority.ContextIdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void OnCoverChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||||
|
MainWin.OnCoverChanged(sender, e);
|
||||||
|
}, DispatcherPriority.ContextIdle);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Initialize()
|
||||||
|
{
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void Connect()
|
||||||
{
|
{
|
||||||
var token = cancelToken.Token;
|
var token = cancelToken.Token;
|
||||||
_connection = await Connect(token);
|
try
|
||||||
_commandConnection = await Connect(token);
|
{
|
||||||
|
_connection = await ConnectInternal(token);
|
||||||
|
_commandConnection = await ConnectInternal(token);
|
||||||
|
}
|
||||||
|
catch(MpcNET.Exceptions.MpcConnectException exception)
|
||||||
|
{
|
||||||
|
Trace.WriteLine("exception: " + exception);
|
||||||
|
}
|
||||||
if (_connection.IsConnected)
|
if (_connection.IsConnected)
|
||||||
{
|
{
|
||||||
_connected = true;
|
_connected = true;
|
||||||
_version = _connection.Version;
|
_version = _connection.Version;
|
||||||
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
Trace.WriteLine("is connected: " + _connected);
|
|
||||||
Trace.WriteLine("version: " + _version);
|
|
||||||
|
|
||||||
await UpdateStatusAsync();
|
await UpdateStatusAsync();
|
||||||
await UpdateSongAsync();
|
await UpdateSongAsync();
|
||||||
@ -85,7 +148,7 @@ namespace unison
|
|||||||
Loop(token);
|
Loop(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<MpcConnection> Connect(CancellationToken token)
|
private async Task<MpcConnection> ConnectInternal(CancellationToken token)
|
||||||
{
|
{
|
||||||
IPAddress.TryParse(Properties.Settings.Default.mpd_host, out IPAddress ipAddress);
|
IPAddress.TryParse(Properties.Settings.Default.mpd_host, out IPAddress ipAddress);
|
||||||
|
|
||||||
@ -95,7 +158,7 @@ namespace unison
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(Properties.Settings.Default.mpd_password))
|
if (!string.IsNullOrEmpty(Properties.Settings.Default.mpd_password))
|
||||||
{
|
{
|
||||||
MpcNET.Message.IMpdMessage<string> result = await connection.SendAsync(new PasswordCommand(Properties.Settings.Default.mpd_password));
|
IMpdMessage<string> result = await connection.SendAsync(new PasswordCommand(Properties.Settings.Default.mpd_password));
|
||||||
if (!result.IsResponseValid)
|
if (!result.IsResponseValid)
|
||||||
{
|
{
|
||||||
string mpdError = result.Response?.Result?.MpdError;
|
string mpdError = result.Response?.Result?.MpdError;
|
||||||
@ -134,6 +197,8 @@ namespace unison
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async Task HandleIdleResponseAsync(string subsystems)
|
private async Task HandleIdleResponseAsync(string subsystems)
|
||||||
|
{
|
||||||
|
try
|
||||||
{
|
{
|
||||||
if (subsystems.Contains("player") || subsystems.Contains("mixer") || subsystems.Contains("output") || subsystems.Contains("options"))
|
if (subsystems.Contains("player") || subsystems.Contains("mixer") || subsystems.Contains("output") || subsystems.Contains("options"))
|
||||||
{
|
{
|
||||||
@ -145,6 +210,34 @@ namespace unison
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateStatusCommand()
|
||||||
|
{
|
||||||
|
if (_commandConnection == null) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
MpdStatus response = await SafelySendCommandAsync(new StatusCommand());
|
||||||
|
|
||||||
|
if (response != null)
|
||||||
|
{
|
||||||
|
CurrentStatus = response;
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
||||||
|
Connect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool _isUpdatingStatus = false;
|
bool _isUpdatingStatus = false;
|
||||||
private async Task UpdateStatusAsync()
|
private async Task UpdateStatusAsync()
|
||||||
@ -156,7 +249,7 @@ namespace unison
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MpcNET.Message.IMpdMessage<MpdStatus> response = await _connection.SendAsync(new StatusCommand());
|
IMpdMessage<MpdStatus> response = await _connection.SendAsync(new StatusCommand());
|
||||||
if (response != null && response.IsResponseValid)
|
if (response != null && response.IsResponseValid)
|
||||||
{
|
{
|
||||||
CurrentStatus = response.Response.Content;
|
CurrentStatus = response.Response.Content;
|
||||||
@ -165,9 +258,10 @@ namespace unison
|
|||||||
else
|
else
|
||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await Connect(cancelToken.Token);
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
||||||
|
Connect();
|
||||||
}
|
}
|
||||||
_isUpdatingStatus = false;
|
_isUpdatingStatus = false;
|
||||||
}
|
}
|
||||||
@ -182,7 +276,7 @@ namespace unison
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MpcNET.Message.IMpdMessage<MpcNET.Types.IMpdFile> response = await _connection.SendAsync(new CurrentSongCommand());
|
IMpdMessage<IMpdFile> response = await _connection.SendAsync(new CurrentSongCommand());
|
||||||
if (response != null && response.IsResponseValid)
|
if (response != null && response.IsResponseValid)
|
||||||
{
|
{
|
||||||
CurrentSong = response.Response.Content;
|
CurrentSong = response.Response.Content;
|
||||||
@ -193,9 +287,10 @@ namespace unison
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
await Connect(cancelToken.Token);
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
||||||
|
Connect();
|
||||||
}
|
}
|
||||||
_isUpdatingSong = false;
|
_isUpdatingSong = false;
|
||||||
}
|
}
|
||||||
@ -247,7 +342,7 @@ namespace unison
|
|||||||
totalBinarySize = response.Size;
|
totalBinarySize = response.Size;
|
||||||
currentSize += response.Binary;
|
currentSize += response.Binary;
|
||||||
data.AddRange(response.Data);
|
data.AddRange(response.Data);
|
||||||
Debug.WriteLine($"Downloading albumart: {currentSize}/{totalBinarySize}");
|
//Debug.WriteLine($"Downloading albumart: {currentSize}/{totalBinarySize}");
|
||||||
} while (currentSize < totalBinarySize && !token.IsCancellationRequested);
|
} while (currentSize < totalBinarySize && !token.IsCancellationRequested);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -260,11 +355,12 @@ namespace unison
|
|||||||
{
|
{
|
||||||
Trace.WriteLine("empty cover");
|
Trace.WriteLine("empty cover");
|
||||||
_cover = null;
|
_cover = null;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
using var stream = new MemoryStream(data.ToArray());
|
{
|
||||||
|
using MemoryStream stream = new MemoryStream(data.ToArray());
|
||||||
_cover = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
_cover = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
||||||
|
}
|
||||||
UpdateCover();
|
UpdateCover();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,20 +371,20 @@ namespace unison
|
|||||||
if (CurrentSong == null)
|
if (CurrentSong == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Trace.WriteLine($"[DEBUG] Song: name[{CurrentSong.Title}] artist[{CurrentSong.Artist}] album[{CurrentSong.Album}] uri[{CurrentSong.Path}]");
|
|
||||||
|
|
||||||
_currentTime = CurrentStatus.Elapsed.TotalSeconds;
|
_currentTime = CurrentStatus.Elapsed.TotalSeconds;
|
||||||
_totalTime = CurrentSong.Time;
|
_totalTime = CurrentSong.Time;
|
||||||
if (!_elapsedTimer.Enabled)
|
if (!_elapsedTimer.Enabled)
|
||||||
_elapsedTimer.Start();
|
_elapsedTimer.Start();
|
||||||
|
|
||||||
|
SongChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
|
||||||
string uri = Regex.Escape(CurrentSong.Path);
|
string uri = Regex.Escape(CurrentSong.Path);
|
||||||
GetAlbumBitmap(uri);
|
GetAlbumBitmap(uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCover()
|
public void UpdateCover()
|
||||||
{
|
{
|
||||||
|
CoverChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateStatus()
|
public void UpdateStatus()
|
||||||
@ -305,62 +401,26 @@ namespace unison
|
|||||||
_currentSingle = CurrentStatus.Single;
|
_currentSingle = CurrentStatus.Single;
|
||||||
_currentVolume = CurrentStatus.Volume;
|
_currentVolume = CurrentStatus.Volume;
|
||||||
|
|
||||||
Trace.WriteLine($"[DEBUG] Status: volume[{CurrentStatus.Volume}] random[{CurrentStatus.Random}] consume[{CurrentStatus.Consume}] State[{CurrentStatus.State}] Bitrate[{CurrentStatus.Bitrate}]");
|
StatusChanged?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MpcNET.Types.IMpdFile GetCurrentSong() => CurrentSong;
|
public IMpdFile GetCurrentSong() => CurrentSong;
|
||||||
public MpdStatus GetStatus() => CurrentStatus;
|
public MpdStatus GetStatus() => CurrentStatus;
|
||||||
public BitmapFrame GetCover() => _cover;
|
public BitmapFrame GetCover() => _cover;
|
||||||
public string GetVersion() => _version;
|
public string GetVersion() => _version;
|
||||||
|
|
||||||
public async void Prev()
|
public async void Prev() => await SafelySendCommandAsync(new PreviousCommand());
|
||||||
{
|
public async void Next() => await SafelySendCommandAsync(new NextCommand());
|
||||||
await SafelySendCommandAsync(new PreviousCommand());
|
public async void PlayPause() =>await SafelySendCommandAsync(new PauseResumeCommand());
|
||||||
}
|
|
||||||
|
|
||||||
public async void Next()
|
public async void Random() => await SafelySendCommandAsync(new RandomCommand(!_currentRandom));
|
||||||
{
|
public async void Repeat() => await SafelySendCommandAsync(new RepeatCommand(!_currentRepeat));
|
||||||
await SafelySendCommandAsync(new NextCommand());
|
public async void Single() => await SafelySendCommandAsync(new SingleCommand(!_currentSingle));
|
||||||
}
|
public async void Consume() => await SafelySendCommandAsync(new ConsumeCommand(!_currentConsume));
|
||||||
|
|
||||||
public async void PlayPause()
|
public async void SetVolume(int value) => await SafelySendCommandAsync(new SetVolumeCommand((byte)value));
|
||||||
{
|
public async void SetTime(double value) => await SafelySendCommandAsync(new SeekCurCommand(value));
|
||||||
await SafelySendCommandAsync(new PauseResumeCommand());
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Random()
|
public bool IsPlaying() => CurrentStatus?.State == MpdState.Play;
|
||||||
{
|
|
||||||
await SafelySendCommandAsync(new RandomCommand(!_currentRandom));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Repeat()
|
|
||||||
{
|
|
||||||
await SafelySendCommandAsync(new RepeatCommand(!_currentRepeat));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Single()
|
|
||||||
{
|
|
||||||
await SafelySendCommandAsync(new SingleCommand(!_currentSingle));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void Consume()
|
|
||||||
{
|
|
||||||
var response2 = await SafelySendCommandAsync(new ConsumeCommand(!_currentConsume));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void SetVolume(int value)
|
|
||||||
{
|
|
||||||
await SafelySendCommandAsync(new SetVolumeCommand((byte)value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public async void SetTime(double value)
|
|
||||||
{
|
|
||||||
await SafelySendCommandAsync(new SeekCurCommand(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsPlaying()
|
|
||||||
{
|
|
||||||
return CurrentStatus?.State == MpdState.Play;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using Hardcodet.Wpf.TaskbarNotification;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using Hardcodet.Wpf.TaskbarNotification;
|
||||||
|
|
||||||
namespace unison
|
namespace unison
|
||||||
{
|
{
|
||||||
@ -9,28 +10,39 @@ namespace unison
|
|||||||
{
|
{
|
||||||
private readonly Process _snapcast = new();
|
private readonly Process _snapcast = new();
|
||||||
public bool Started { get; private set; }
|
public bool Started { get; private set; }
|
||||||
private string _snapcastPath;
|
|
||||||
|
|
||||||
public SnapcastHandler()
|
public SnapcastHandler()
|
||||||
{
|
{
|
||||||
// wip: this will have to be moved after the mpd connection, later on
|
|
||||||
_snapcastPath = Properties.Settings.Default.snapcast_path;
|
|
||||||
if (Properties.Settings.Default.snapcast_startup)
|
|
||||||
Start();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateSystray()
|
public void OnConnectionChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (Properties.Settings.Default.snapcast_startup)
|
||||||
|
{
|
||||||
|
var mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
|
if (mpd._connected)
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateInterface()
|
||||||
{
|
{
|
||||||
TaskbarIcon Systray = (TaskbarIcon)Application.Current.Properties["systray"];
|
TaskbarIcon Systray = (TaskbarIcon)Application.Current.Properties["systray"];
|
||||||
SystrayViewModel DataContext = Systray.DataContext as SystrayViewModel;
|
SystrayViewModel DataContext = Systray.DataContext as SystrayViewModel;
|
||||||
DataContext.OnPropertyChanged("SnapcastText");
|
DataContext.OnPropertyChanged("SnapcastText");
|
||||||
|
|
||||||
|
Application.Current.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
||||||
|
MainWin.OnSnapcastChanged();
|
||||||
|
}, DispatcherPriority.ContextIdle);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
{
|
||||||
if (!Started)
|
if (!Started)
|
||||||
{
|
{
|
||||||
_snapcast.StartInfo.FileName = _snapcastPath + @"\snapclient.exe";
|
_snapcast.StartInfo.FileName = Properties.Settings.Default.snapcast_path + @"\snapclient.exe";
|
||||||
_snapcast.StartInfo.Arguments = $"--host {Properties.Settings.Default.mpd_host}";
|
_snapcast.StartInfo.Arguments = $"--host {Properties.Settings.Default.mpd_host}";
|
||||||
_snapcast.StartInfo.CreateNoWindow = true;
|
_snapcast.StartInfo.CreateNoWindow = true;
|
||||||
try
|
try
|
||||||
@ -39,19 +51,19 @@ namespace unison
|
|||||||
}
|
}
|
||||||
catch (Exception err)
|
catch (Exception err)
|
||||||
{
|
{
|
||||||
MessageBox.Show($"[Snapcast error]\nInvalid path: {err.Message}\n\nCurrent path: {_snapcastPath}\nYou can reset it in the settings if needed.",
|
MessageBox.Show($"[Snapcast error]\nInvalid path: {err.Message}\n\nCurrent path: {Properties.Settings.Default.snapcast_path}\nYou can reset it in the settings if needed.",
|
||||||
"unison", MessageBoxButton.OK, MessageBoxImage.Error);
|
"unison", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
Trace.WriteLine(err.Message);
|
Trace.WriteLine(err.Message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Started = true;
|
Started = true;
|
||||||
UpdateSystray();
|
UpdateInterface();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_snapcast.Kill();
|
_snapcast.Kill();
|
||||||
Started = false;
|
Started = false;
|
||||||
UpdateSystray();
|
UpdateInterface();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +73,7 @@ namespace unison
|
|||||||
{
|
{
|
||||||
_snapcast.Kill();
|
_snapcast.Kill();
|
||||||
Started = false;
|
Started = false;
|
||||||
UpdateSystray();
|
UpdateInterface();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,11 @@
|
|||||||
<TextBlock x:Name="SongTitle" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="20" Text="Title"/>
|
<TextBlock x:Name="SongTitle" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="20" Text="Title"/>
|
||||||
<TextBlock x:Name="SongArtist" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold" FontSize="18" Text="Artist"/>
|
<TextBlock x:Name="SongArtist" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Bold" FontSize="18" Text="Artist"/>
|
||||||
<TextBlock x:Name="SongAlbum" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="16" Text="Album"/>
|
<TextBlock x:Name="SongAlbum" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" FontSize="16" Text="Album"/>
|
||||||
<TextBlock x:Name="Bitrate" TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" Text="Bitrate" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}"/>
|
<TextBlock TextWrapping="Wrap" TextAlignment="Center" FontWeight="Normal" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" Margin="0,2,0,0">
|
||||||
|
<Run x:Name="SongGenre"/>
|
||||||
|
<Run> – </Run>
|
||||||
|
<Run x:Name="Format"/>
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid x:Name="Controls" VerticalAlignment="Top" Margin="10,95,10,0">
|
<Grid x:Name="Controls" VerticalAlignment="Top" Margin="10,95,10,0">
|
||||||
@ -99,7 +103,7 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid x:Name="BottomLayout" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" Width="Auto" MinHeight="40">
|
<Grid x:Name="BottomLayout" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Background="{DynamicResource {x:Static SystemColors.ControlLightBrushKey}}" Width="Auto" MinHeight="40">
|
||||||
<Button x:Name="Snapcast" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Snapcast_Clicked" Margin="10,0,0,0" Padding="5, 2" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}">
|
<Button x:Name="Snapcast" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Snapcast_Clicked" Margin="10,0,0,0" Padding="5, 2" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}" IsEnabled="False">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<emoji:TextBlock Text="🔊" Padding="0,0,0,2"/>
|
<emoji:TextBlock Text="🔊" Padding="0,0,0,2"/>
|
||||||
<TextBlock x:Name="SnapcastText" Text="Start Snapcast" Margin="5, 0, 0, 0"/>
|
<TextBlock x:Name="SnapcastText" Text="Start Snapcast" Margin="5, 0, 0, 0"/>
|
||||||
|
@ -12,7 +12,7 @@ namespace unison
|
|||||||
{
|
{
|
||||||
public readonly Settings SettingsWindow = new Settings();
|
public readonly Settings SettingsWindow = new Settings();
|
||||||
|
|
||||||
private MPDHandler mpd;
|
private readonly MPDHandler mpd;
|
||||||
|
|
||||||
Thickness SelectedThickness;
|
Thickness SelectedThickness;
|
||||||
Thickness BaseThickness;
|
Thickness BaseThickness;
|
||||||
@ -38,7 +38,11 @@ namespace unison
|
|||||||
|
|
||||||
private void Timer_Tick(object sender, EventArgs e)
|
private void Timer_Tick(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
UpdateInterface();
|
if (mpd.GetCurrentSong() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
CurrentTime.Text = FormatSeconds(mpd._currentTime);
|
||||||
|
TimeSlider.Value = mpd._currentTime / mpd.GetCurrentSong().Time * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateButton(ref Border border, bool b)
|
public void UpdateButton(ref Border border, bool b)
|
||||||
@ -60,24 +64,39 @@ namespace unison
|
|||||||
return timespan.ToString(@"mm\:ss");
|
return timespan.ToString(@"mm\:ss");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateInterface()
|
public void OnConnectionChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (mpd.GetCurrentSong() == null || mpd.GetStatus() == null)
|
Connection.Text = (mpd._connected ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
||||||
|
SettingsWindow.UpdateConnectionStatus();
|
||||||
|
if (mpd._connected)
|
||||||
|
Snapcast.IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSongChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (mpd.GetCurrentSong() == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (!mpd.GetCurrentSong().HasName)
|
||||||
|
SongTitle.Text = mpd.GetCurrentSong().Title;
|
||||||
|
else
|
||||||
SongTitle.Text = mpd.GetCurrentSong().Title;
|
SongTitle.Text = mpd.GetCurrentSong().Title;
|
||||||
SongTitle.ToolTip = mpd.GetCurrentSong().Path;
|
SongTitle.ToolTip = mpd.GetCurrentSong().Path;
|
||||||
SongArtist.Text = mpd.GetCurrentSong().Artist;
|
SongArtist.Text = mpd.GetCurrentSong().Artist;
|
||||||
SongAlbum.Text = mpd.GetCurrentSong().Album;
|
SongAlbum.Text = mpd.GetCurrentSong().Album;
|
||||||
|
SongGenre.Text = mpd.GetCurrentSong().Genre;
|
||||||
|
|
||||||
if (mpd.GetCurrentSong().Date != null)
|
if (mpd.GetCurrentSong().Date != null)
|
||||||
SongAlbum.Text += $" ({ mpd.GetCurrentSong().Date})";
|
SongAlbum.Text += $" ({ mpd.GetCurrentSong().Date})";
|
||||||
Bitrate.Text = mpd.GetCurrentSong().Path.Substring(mpd.GetCurrentSong().Path.LastIndexOf(".") + 1) + " – ";
|
Format.Text = mpd.GetCurrentSong().Path.Substring(mpd.GetCurrentSong().Path.LastIndexOf(".") + 1);
|
||||||
Bitrate.Text += mpd.GetStatus().Bitrate + "kbps";
|
|
||||||
|
|
||||||
CurrentTime.Text = FormatSeconds(mpd._currentTime);
|
|
||||||
EndTime.Text = FormatSeconds(mpd.GetCurrentSong().Time);
|
EndTime.Text = FormatSeconds(mpd.GetCurrentSong().Time);
|
||||||
|
}
|
||||||
|
|
||||||
TimeSlider.Value = mpd._currentTime / mpd.GetCurrentSong().Time * 100;
|
public void OnStatusChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (mpd.GetStatus() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
if (VolumeSlider.Value != mpd._currentVolume)
|
if (VolumeSlider.Value != mpd._currentVolume)
|
||||||
{
|
{
|
||||||
@ -90,13 +109,14 @@ namespace unison
|
|||||||
else
|
else
|
||||||
PlayPause.Text = "\xedb5";
|
PlayPause.Text = "\xedb5";
|
||||||
|
|
||||||
Connection.Text = (mpd._connected ? "✔️" : "❌") + $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
|
||||||
|
|
||||||
UpdateButton(ref BorderRandom, mpd._currentRandom);
|
UpdateButton(ref BorderRandom, mpd._currentRandom);
|
||||||
UpdateButton(ref BorderRepeat, mpd._currentRepeat);
|
UpdateButton(ref BorderRepeat, mpd._currentRepeat);
|
||||||
UpdateButton(ref BorderSingle, mpd._currentSingle);
|
UpdateButton(ref BorderSingle, mpd._currentSingle);
|
||||||
UpdateButton(ref BorderConsume, mpd._currentConsume);
|
UpdateButton(ref BorderConsume, mpd._currentConsume);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCoverChanged(object sender, EventArgs e)
|
||||||
|
{
|
||||||
if (mpd.GetCover() == null)
|
if (mpd.GetCover() == null)
|
||||||
{
|
{
|
||||||
NoCover.Visibility = Visibility.Visible;
|
NoCover.Visibility = Visibility.Visible;
|
||||||
@ -108,7 +128,10 @@ namespace unison
|
|||||||
Cover.Visibility = Visibility.Visible;
|
Cover.Visibility = Visibility.Visible;
|
||||||
NoCover.Visibility = Visibility.Collapsed;
|
NoCover.Visibility = Visibility.Collapsed;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnSnapcastChanged()
|
||||||
|
{
|
||||||
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
|
||||||
if (snapcast.Started)
|
if (snapcast.Started)
|
||||||
SnapcastText.Text = "Stop Snapcast";
|
SnapcastText.Text = "Stop Snapcast";
|
||||||
|
@ -46,7 +46,7 @@ namespace unison
|
|||||||
|
|
||||||
MpdHost.Text = Properties.Settings.Default.mpd_host;
|
MpdHost.Text = Properties.Settings.Default.mpd_host;
|
||||||
MpdPort.Text = Properties.Settings.Default.mpd_port.ToString();
|
MpdPort.Text = Properties.Settings.Default.mpd_port.ToString();
|
||||||
MpdPassword.Text = null; //Properties.Settings.Default.mpd_password;
|
MpdPassword.Text = Properties.Settings.Default.mpd_password;
|
||||||
SnapcastStartup.IsChecked = Properties.Settings.Default.snapcast_startup;
|
SnapcastStartup.IsChecked = Properties.Settings.Default.snapcast_startup;
|
||||||
SnapcastPath.Text = Properties.Settings.Default.snapcast_path;
|
SnapcastPath.Text = Properties.Settings.Default.snapcast_path;
|
||||||
SnapcastPort.Text = Properties.Settings.Default.snapcast_port.ToString();
|
SnapcastPort.Text = Properties.Settings.Default.snapcast_port.ToString();
|
||||||
@ -71,18 +71,17 @@ namespace unison
|
|||||||
{
|
{
|
||||||
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
if (mpd._connected)
|
if (mpd._connected)
|
||||||
{
|
|
||||||
ConnectionStatus.Text = "Connected to MPD " + mpd.GetVersion() + ".";
|
ConnectionStatus.Text = "Connected to MPD " + mpd.GetVersion() + ".";
|
||||||
ConnectButton.IsEnabled = false;
|
else
|
||||||
}
|
ConnectionStatus.Text = "Not connected.";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MPDConnect_Clicked(object sender, RoutedEventArgs e)
|
private void MPDConnect_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
SaveSettings();
|
SaveSettings();
|
||||||
|
ConnectionStatus.Text = "Connecting...";
|
||||||
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
// connect to mpd
|
mpd.Connect();
|
||||||
UpdateConnectionStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SnapcastReset_Clicked(object sender, RoutedEventArgs e)
|
private void SnapcastReset_Clicked(object sender, RoutedEventArgs e)
|
||||||
@ -95,7 +94,7 @@ namespace unison
|
|||||||
{
|
{
|
||||||
Properties.Settings.Default.mpd_host = MpdHost.Text;
|
Properties.Settings.Default.mpd_host = MpdHost.Text;
|
||||||
Properties.Settings.Default.mpd_port = int.Parse(MpdPort.Text, CultureInfo.InvariantCulture);
|
Properties.Settings.Default.mpd_port = int.Parse(MpdPort.Text, CultureInfo.InvariantCulture);
|
||||||
Properties.Settings.Default.mpd_password = null;//MpdPassword.Text;
|
Properties.Settings.Default.mpd_password = MpdPassword.Text;
|
||||||
Properties.Settings.Default.snapcast_startup = (bool)SnapcastStartup.IsChecked;
|
Properties.Settings.Default.snapcast_startup = (bool)SnapcastStartup.IsChecked;
|
||||||
Properties.Settings.Default.snapcast_path = SnapcastPath.Text;
|
Properties.Settings.Default.snapcast_path = SnapcastPath.Text;
|
||||||
Properties.Settings.Default.snapcast_port = int.Parse(SnapcastPort.Text, CultureInfo.InvariantCulture);
|
Properties.Settings.Default.snapcast_port = int.Parse(SnapcastPort.Text, CultureInfo.InvariantCulture);
|
||||||
|
Loading…
Reference in New Issue
Block a user