2021-08-19 20:00:25 +00:00
|
|
|
|
using System;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
using System.Collections.Generic;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
using System.Diagnostics;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using System.Threading;
|
2021-08-16 00:13:47 +00:00
|
|
|
|
using System.Threading.Tasks;
|
2021-08-30 23:30:00 +00:00
|
|
|
|
using System.Windows;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
using System.Windows.Media.Imaging;
|
2021-09-01 22:14:28 +00:00
|
|
|
|
using System.Windows.Threading;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
using MpcNET;
|
|
|
|
|
using MpcNET.Commands.Database;
|
|
|
|
|
using MpcNET.Commands.Playback;
|
2021-10-01 00:24:18 +00:00
|
|
|
|
using MpcNET.Commands.Queue;
|
2021-10-03 15:20:14 +00:00
|
|
|
|
using MpcNET.Commands.Reflection;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
using MpcNET.Commands.Status;
|
2021-08-30 23:30:00 +00:00
|
|
|
|
using MpcNET.Message;
|
|
|
|
|
using MpcNET.Types;
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
|
|
|
|
namespace unison
|
2021-08-13 23:20:38 +00:00
|
|
|
|
{
|
2021-10-05 12:18:58 +00:00
|
|
|
|
public class Statistics
|
|
|
|
|
{
|
|
|
|
|
public int Songs { get; set; }
|
|
|
|
|
public int Albums { get; set; }
|
|
|
|
|
public int Artists { get; set; }
|
|
|
|
|
public string TotalPlaytime { get; set; }
|
|
|
|
|
public string Uptime { get; set; }
|
|
|
|
|
public string TotalTimePlayed { get; set; }
|
|
|
|
|
public string DatabaseUpdate { get; set; }
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-13 23:20:38 +00:00
|
|
|
|
public class MPDHandler
|
|
|
|
|
{
|
2021-09-01 00:35:37 +00:00
|
|
|
|
private bool _connected;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
public string _version;
|
2021-09-01 00:35:37 +00:00
|
|
|
|
private int _currentVolume;
|
2021-10-04 17:20:41 +00:00
|
|
|
|
private int _previousVolume;
|
2021-09-01 00:35:37 +00:00
|
|
|
|
private bool _currentRandom;
|
|
|
|
|
private bool _currentRepeat;
|
|
|
|
|
private bool _currentSingle;
|
|
|
|
|
private bool _currentConsume;
|
|
|
|
|
private double _currentTime;
|
|
|
|
|
private double _totalTime;
|
|
|
|
|
|
|
|
|
|
private MpdStatus _currentStatus;
|
|
|
|
|
private IMpdFile _currentSong;
|
|
|
|
|
private BitmapFrame _cover;
|
2021-10-05 12:18:58 +00:00
|
|
|
|
public Statistics _stats;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
private readonly System.Timers.Timer _elapsedTimer;
|
2021-09-01 22:14:28 +00:00
|
|
|
|
private DispatcherTimer _retryTimer;
|
2021-09-01 00:35:37 +00:00
|
|
|
|
|
2021-09-02 22:21:15 +00:00
|
|
|
|
bool _isUpdatingStatus = false;
|
|
|
|
|
bool _isUpdatingSong = false;
|
|
|
|
|
|
2022-04-01 12:07:58 +00:00
|
|
|
|
bool _invalidIp = false;
|
|
|
|
|
|
2021-09-01 00:35:37 +00:00
|
|
|
|
private event EventHandler ConnectionChanged;
|
|
|
|
|
private event EventHandler StatusChanged;
|
|
|
|
|
private event EventHandler SongChanged;
|
|
|
|
|
private event EventHandler CoverChanged;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
private MpcConnection _connection;
|
2021-08-29 18:50:47 +00:00
|
|
|
|
private MpcConnection _commandConnection;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
private IPEndPoint _mpdEndpoint;
|
|
|
|
|
private CancellationTokenSource cancelToken;
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-08-13 23:20:38 +00:00
|
|
|
|
public MPDHandler()
|
|
|
|
|
{
|
2021-08-28 22:32:41 +00:00
|
|
|
|
cancelToken = new CancellationTokenSource();
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
Initialize(null, null);
|
|
|
|
|
|
2021-10-05 12:18:58 +00:00
|
|
|
|
_stats = new Statistics();
|
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
_retryTimer = new DispatcherTimer();
|
|
|
|
|
_retryTimer.Interval = TimeSpan.FromSeconds(5);
|
|
|
|
|
_retryTimer.Tick += Initialize;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
|
|
|
|
_elapsedTimer = new System.Timers.Timer(500);
|
|
|
|
|
_elapsedTimer.Elapsed += new System.Timers.ElapsedEventHandler(ElapsedTimer);
|
2021-08-30 23:30:00 +00:00
|
|
|
|
|
|
|
|
|
ConnectionChanged += OnConnectionChanged;
|
|
|
|
|
StatusChanged += OnStatusChanged;
|
|
|
|
|
SongChanged += OnSongChanged;
|
|
|
|
|
CoverChanged += OnCoverChanged;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-01 00:35:37 +00:00
|
|
|
|
private void ElapsedTimer(object sender, System.Timers.ElapsedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
if ((_currentTime < _totalTime || _totalTime == -1) && (_currentStatus.State == MpdState.Play))
|
|
|
|
|
_currentTime += 0.5;
|
|
|
|
|
else
|
|
|
|
|
_elapsedTimer.Stop();
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
void OnConnectionChanged(object sender, EventArgs e)
|
2021-08-30 23:30:00 +00:00
|
|
|
|
{
|
2022-04-01 12:07:58 +00:00
|
|
|
|
if (!_connected && !_invalidIp)
|
2021-09-01 22:14:28 +00:00
|
|
|
|
_retryTimer.Start();
|
|
|
|
|
else
|
|
|
|
|
_retryTimer.Stop();
|
|
|
|
|
|
2021-08-30 23:30:00 +00:00
|
|
|
|
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);
|
2021-09-01 00:35:37 +00:00
|
|
|
|
});
|
2021-08-30 23:30:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnStatusChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
|
|
|
|
MainWin.OnStatusChanged(sender, e);
|
2021-09-01 00:35:37 +00:00
|
|
|
|
});
|
2021-08-30 23:30:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnSongChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
|
|
|
|
MainWin.OnSongChanged(sender, e);
|
2021-09-01 00:35:37 +00:00
|
|
|
|
});
|
2021-08-30 23:30:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void OnCoverChanged(object sender, EventArgs e)
|
|
|
|
|
{
|
|
|
|
|
Application.Current.Dispatcher.Invoke(() =>
|
|
|
|
|
{
|
|
|
|
|
MainWindow MainWin = (MainWindow)Application.Current.MainWindow;
|
|
|
|
|
MainWin.OnCoverChanged(sender, e);
|
2021-09-01 00:35:37 +00:00
|
|
|
|
});
|
2021-08-19 20:00:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 22:21:15 +00:00
|
|
|
|
public void SendCommand<T>(IMpcCommand<T> command)
|
|
|
|
|
{
|
|
|
|
|
Task.Run(async () =>
|
|
|
|
|
{
|
|
|
|
|
await SafelySendCommandAsync(command);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async Task<T> SafelySendCommandAsync<T>(IMpcCommand<T> command)
|
|
|
|
|
{
|
|
|
|
|
if (_commandConnection == null)
|
|
|
|
|
{
|
|
|
|
|
Trace.WriteLine("[SafelySendCommandAsync] no command connection");
|
|
|
|
|
return default(T);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
IMpdMessage<T> response = await _commandConnection.SendAsync(command);
|
|
|
|
|
if (!response.IsResponseValid)
|
|
|
|
|
{
|
|
|
|
|
var mpdError = response.Response?.Result?.MpdError;
|
|
|
|
|
if (mpdError != null && mpdError != "")
|
|
|
|
|
throw new Exception(mpdError);
|
|
|
|
|
else
|
|
|
|
|
throw new Exception($"Invalid server response: {response}.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response.Response.Content;
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Trace.WriteLine($"Sending {command.GetType().Name} failed: {e.Message}");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return default(T);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
private void Initialize(object sender, EventArgs e)
|
2021-08-30 23:30:00 +00:00
|
|
|
|
{
|
2021-09-01 22:14:28 +00:00
|
|
|
|
if (!_connected)
|
|
|
|
|
Connect();
|
2021-08-30 23:30:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async void Connect()
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-09-01 00:35:37 +00:00
|
|
|
|
CancellationToken token = cancelToken.Token;
|
2021-08-30 23:30:00 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_connection = await ConnectInternal(token);
|
|
|
|
|
_commandConnection = await ConnectInternal(token);
|
|
|
|
|
}
|
2022-04-01 12:07:58 +00:00
|
|
|
|
catch(MpcNET.Exceptions.MpcConnectException)
|
2021-08-30 23:30:00 +00:00
|
|
|
|
{
|
2022-04-01 12:07:58 +00:00
|
|
|
|
_invalidIp = true;
|
2021-08-30 23:30:00 +00:00
|
|
|
|
}
|
2021-09-01 22:14:28 +00:00
|
|
|
|
if (_connection != null && _commandConnection != null)
|
|
|
|
|
{
|
2022-04-01 12:07:58 +00:00
|
|
|
|
_invalidIp = false;
|
2021-09-01 22:14:28 +00:00
|
|
|
|
if (_connection.IsConnected && _commandConnection.IsConnected)
|
|
|
|
|
{
|
|
|
|
|
_connected = true;
|
|
|
|
|
_version = _connection.Version;
|
|
|
|
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2021-08-28 22:32:41 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
2021-09-01 22:14:28 +00:00
|
|
|
|
return;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
await UpdateStatusAsync();
|
|
|
|
|
await UpdateSongAsync();
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
Loop(token);
|
2021-08-19 20:00:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-30 23:30:00 +00:00
|
|
|
|
private async Task<MpcConnection> ConnectInternal(CancellationToken token)
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-08-28 22:32:41 +00:00
|
|
|
|
IPAddress.TryParse(Properties.Settings.Default.mpd_host, out IPAddress ipAddress);
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2022-04-01 12:07:58 +00:00
|
|
|
|
if (ipAddress == null)
|
|
|
|
|
{
|
|
|
|
|
IPAddress[] addrList;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
addrList = Dns.GetHostAddresses(Properties.Settings.Default.mpd_host);
|
|
|
|
|
if (addrList.Length > 0)
|
|
|
|
|
ipAddress = addrList[0];
|
|
|
|
|
}
|
|
|
|
|
catch (Exception)
|
|
|
|
|
{
|
|
|
|
|
throw new MpcNET.Exceptions.MpcConnectException("No correct IP provided by user.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
_mpdEndpoint = new IPEndPoint(ipAddress, Properties.Settings.Default.mpd_port);
|
|
|
|
|
MpcConnection connection = new MpcConnection(_mpdEndpoint);
|
|
|
|
|
await connection.ConnectAsync(token);
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-09-02 17:47:55 +00:00
|
|
|
|
/*if (!string.IsNullOrEmpty(Properties.Settings.Default.mpd_password))
|
2021-08-28 22:32:41 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
IMpdMessage<string> result = await connection.SendAsync(new PasswordCommand(Properties.Settings.Default.mpd_password));
|
2021-08-28 22:32:41 +00:00
|
|
|
|
if (!result.IsResponseValid)
|
|
|
|
|
{
|
|
|
|
|
string mpdError = result.Response?.Result?.MpdError;
|
2021-09-01 00:35:37 +00:00
|
|
|
|
Trace.WriteLine(mpdError);
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
2021-09-02 17:47:55 +00:00
|
|
|
|
}*/
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
return connection;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 22:21:15 +00:00
|
|
|
|
private void Disconnected()
|
|
|
|
|
{
|
|
|
|
|
_connected = false;
|
|
|
|
|
|
|
|
|
|
_connection = null;
|
|
|
|
|
_commandConnection = null;
|
|
|
|
|
|
|
|
|
|
ConnectionChanged?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
private void Loop(CancellationToken token)
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-08-28 22:32:41 +00:00
|
|
|
|
Task.Run(async () =>
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (token.IsCancellationRequested || _connection == null)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
var idleChanges = await _connection.SendAsync(new IdleCommand("stored_playlist playlist player mixer output options"));
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
if (idleChanges.IsResponseValid)
|
|
|
|
|
await HandleIdleResponseAsync(idleChanges.Response.Content);
|
|
|
|
|
else
|
|
|
|
|
throw new Exception(idleChanges.Response?.Content);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2021-09-01 22:14:28 +00:00
|
|
|
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
|
|
|
|
Disconnected();
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}).ConfigureAwait(false);
|
2021-08-19 20:00:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
private async Task HandleIdleResponseAsync(string subsystems)
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (subsystems.Contains("player") || subsystems.Contains("mixer") || subsystems.Contains("output") || subsystems.Contains("options"))
|
|
|
|
|
{
|
|
|
|
|
await UpdateStatusAsync();
|
|
|
|
|
|
|
|
|
|
if (subsystems.Contains("player"))
|
|
|
|
|
await UpdateSongAsync();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
private async Task UpdateStatusAsync()
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-09-02 22:21:15 +00:00
|
|
|
|
if (_connection == null || _isUpdatingStatus)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
_isUpdatingStatus = true;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
try
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
IMpdMessage<MpdStatus> response = await _connection.SendAsync(new StatusCommand());
|
2021-08-28 22:32:41 +00:00
|
|
|
|
if (response != null && response.IsResponseValid)
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-09-01 00:35:37 +00:00
|
|
|
|
_currentStatus = response.Response.Content;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
UpdateStatus();
|
|
|
|
|
}
|
2021-08-28 22:32:41 +00:00
|
|
|
|
else
|
|
|
|
|
throw new Exception();
|
|
|
|
|
}
|
2021-08-30 23:30:00 +00:00
|
|
|
|
catch (Exception e)
|
2021-08-28 22:32:41 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
2021-08-16 00:13:47 +00:00
|
|
|
|
}
|
2021-09-02 22:21:15 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
_isUpdatingStatus = false;
|
2021-08-16 00:13:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
private async Task UpdateSongAsync()
|
2021-08-16 00:13:47 +00:00
|
|
|
|
{
|
2021-09-02 22:21:15 +00:00
|
|
|
|
if (_connection == null || _isUpdatingSong)
|
|
|
|
|
return;
|
2021-08-29 18:50:47 +00:00
|
|
|
|
|
|
|
|
|
_isUpdatingSong = true;
|
|
|
|
|
|
|
|
|
|
try
|
2021-08-28 22:32:41 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
IMpdMessage<IMpdFile> response = await _connection.SendAsync(new CurrentSongCommand());
|
2021-08-29 18:50:47 +00:00
|
|
|
|
if (response != null && response.IsResponseValid)
|
|
|
|
|
{
|
2021-09-01 00:35:37 +00:00
|
|
|
|
_currentSong = response.Response.Content;
|
2021-08-29 18:50:47 +00:00
|
|
|
|
UpdateSong();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
throw new Exception();
|
|
|
|
|
}
|
2021-08-30 23:30:00 +00:00
|
|
|
|
catch (Exception e)
|
2021-08-29 18:50:47 +00:00
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
Trace.WriteLine($"Error in Idle connection thread: {e.Message}");
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 22:21:15 +00:00
|
|
|
|
_isUpdatingSong = false;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-09-02 22:21:15 +00:00
|
|
|
|
private async void GetAlbumCover(string path, CancellationToken token = default)
|
2021-08-28 22:32:41 +00:00
|
|
|
|
{
|
|
|
|
|
List<byte> data = new List<byte>();
|
|
|
|
|
try
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2021-08-28 22:32:41 +00:00
|
|
|
|
long totalBinarySize = 9999;
|
|
|
|
|
long currentSize = 0;
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
do
|
2021-08-19 20:00:25 +00:00
|
|
|
|
{
|
2022-03-30 22:27:33 +00:00
|
|
|
|
if (_connection == null)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
var albumReq = await _connection.SendAsync(new AlbumArtCommand(path, currentSize));
|
2021-09-02 17:47:55 +00:00
|
|
|
|
if (!albumReq.IsResponseValid)
|
|
|
|
|
break;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
|
|
|
|
|
var response = albumReq.Response.Content;
|
2021-09-02 17:47:55 +00:00
|
|
|
|
if (response.Binary == 0)
|
|
|
|
|
break;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
|
|
|
|
|
totalBinarySize = response.Size;
|
|
|
|
|
currentSize += response.Binary;
|
|
|
|
|
data.AddRange(response.Data);
|
|
|
|
|
} while (currentSize < totalBinarySize && !token.IsCancellationRequested);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2021-09-01 00:35:37 +00:00
|
|
|
|
Trace.WriteLine("Exception caught while getting albumart: " + e);
|
2021-08-28 22:32:41 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (data.Count == 0)
|
|
|
|
|
_cover = null;
|
2021-08-30 23:30:00 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
using MemoryStream stream = new MemoryStream(data.ToArray());
|
2021-10-03 11:54:54 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
_cover = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
|
|
|
|
|
}
|
2021-10-04 12:06:20 +00:00
|
|
|
|
catch (System.NotSupportedException)
|
2021-10-03 11:54:54 +00:00
|
|
|
|
{
|
|
|
|
|
_cover = null;
|
|
|
|
|
}
|
2021-08-30 23:30:00 +00:00
|
|
|
|
}
|
2021-08-28 22:32:41 +00:00
|
|
|
|
UpdateCover();
|
2021-08-16 00:13:47 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 22:21:15 +00:00
|
|
|
|
public void UpdateStatus()
|
2021-08-16 00:13:47 +00:00
|
|
|
|
{
|
2021-09-02 22:21:15 +00:00
|
|
|
|
if (!_connected || _currentStatus == null)
|
2021-08-16 00:13:47 +00:00
|
|
|
|
return;
|
2021-09-02 22:21:15 +00:00
|
|
|
|
|
|
|
|
|
_currentRandom = _currentStatus.Random;
|
|
|
|
|
_currentRepeat = _currentStatus.Repeat;
|
|
|
|
|
_currentConsume = _currentStatus.Consume;
|
|
|
|
|
_currentSingle = _currentStatus.Single;
|
|
|
|
|
_currentVolume = _currentStatus.Volume;
|
|
|
|
|
|
|
|
|
|
StatusChanged?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void UpdateSong()
|
|
|
|
|
{
|
|
|
|
|
if (!_connected || _currentSong == null)
|
2021-08-28 22:32:41 +00:00
|
|
|
|
return;
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-09-01 00:35:37 +00:00
|
|
|
|
_currentTime = _currentStatus.Elapsed.TotalSeconds;
|
|
|
|
|
_totalTime = _currentSong.Time;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
if (!_elapsedTimer.Enabled)
|
|
|
|
|
_elapsedTimer.Start();
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-30 23:30:00 +00:00
|
|
|
|
SongChanged?.Invoke(this, EventArgs.Empty);
|
|
|
|
|
|
2021-09-01 00:35:37 +00:00
|
|
|
|
string uri = Regex.Escape(_currentSong.Path);
|
2021-09-02 22:21:15 +00:00
|
|
|
|
GetAlbumCover(uri);
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-08-28 22:32:41 +00:00
|
|
|
|
public void UpdateCover()
|
|
|
|
|
{
|
2021-08-30 23:30:00 +00:00
|
|
|
|
CoverChanged?.Invoke(this, EventArgs.Empty);
|
2021-08-28 22:32:41 +00:00
|
|
|
|
}
|
2021-08-19 20:00:25 +00:00
|
|
|
|
|
2021-09-01 00:35:37 +00:00
|
|
|
|
public IMpdFile GetCurrentSong() => _currentSong;
|
|
|
|
|
public MpdStatus GetStatus() => _currentStatus;
|
2021-08-28 22:32:41 +00:00
|
|
|
|
public BitmapFrame GetCover() => _cover;
|
|
|
|
|
public string GetVersion() => _version;
|
2021-10-05 12:18:58 +00:00
|
|
|
|
public Statistics GetStats() => _stats;
|
2021-09-01 00:35:37 +00:00
|
|
|
|
public double GetCurrentTime() => _currentTime;
|
|
|
|
|
|
|
|
|
|
public bool IsConnected() => _connected;
|
|
|
|
|
public bool IsPlaying() => _currentStatus?.State == MpdState.Play;
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
public void Prev() => SendCommand(new PreviousCommand());
|
|
|
|
|
public void Next() => SendCommand(new NextCommand());
|
|
|
|
|
public void PlayPause() => SendCommand(new PauseResumeCommand());
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
public void Random() => SendCommand(new RandomCommand(!_currentRandom));
|
|
|
|
|
public void Repeat() => SendCommand(new RepeatCommand(!_currentRepeat));
|
|
|
|
|
public void Single() => SendCommand(new SingleCommand(!_currentSingle));
|
|
|
|
|
public void Consume() => SendCommand(new ConsumeCommand(!_currentConsume));
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-09-01 22:14:28 +00:00
|
|
|
|
public void SetTime(double value) => SendCommand(new SeekCurCommand(value));
|
|
|
|
|
public void SetVolume(int value) => SendCommand(new SetVolumeCommand((byte)value));
|
2021-09-01 00:35:37 +00:00
|
|
|
|
|
|
|
|
|
public void VolumeUp()
|
|
|
|
|
{
|
|
|
|
|
_currentVolume += Properties.Settings.Default.volume_offset;
|
|
|
|
|
if (_currentVolume > 100)
|
|
|
|
|
_currentVolume = 100;
|
|
|
|
|
SetVolume(_currentVolume);
|
|
|
|
|
}
|
2021-08-16 00:13:47 +00:00
|
|
|
|
|
2021-09-01 00:35:37 +00:00
|
|
|
|
public void VolumeDown()
|
|
|
|
|
{
|
|
|
|
|
_currentVolume -= Properties.Settings.Default.volume_offset;
|
|
|
|
|
if (_currentVolume < 0)
|
|
|
|
|
_currentVolume = 0;
|
|
|
|
|
SetVolume(_currentVolume);
|
|
|
|
|
}
|
2021-10-01 00:24:18 +00:00
|
|
|
|
|
2021-10-04 17:20:41 +00:00
|
|
|
|
public void VolumeMute()
|
|
|
|
|
{
|
|
|
|
|
if (_currentVolume == 0)
|
|
|
|
|
{
|
|
|
|
|
_currentVolume = _previousVolume;
|
|
|
|
|
_previousVolume = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_previousVolume = _currentVolume;
|
|
|
|
|
_currentVolume = 0;
|
|
|
|
|
}
|
|
|
|
|
SetVolume(_currentVolume);
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-01 00:24:18 +00:00
|
|
|
|
public void ClearQueue() => SendCommand(new ClearCommand());
|
|
|
|
|
public void PlayCommand() => SendCommand(new PlayCommand(0));
|
|
|
|
|
|
|
|
|
|
public void AddSong(string Uri)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("AddCommand path: " + Uri);
|
|
|
|
|
SendCommand(new AddCommand(Uri));
|
|
|
|
|
}
|
2021-10-03 15:20:14 +00:00
|
|
|
|
|
|
|
|
|
public void ClearAddAndPlay(string Uri)
|
|
|
|
|
{
|
|
|
|
|
CommandList commandList = new CommandList(new IMpcCommand<object>[] { new ClearCommand(), new AddCommand(Uri), new PlayCommand(0) });
|
|
|
|
|
SendCommand(commandList);
|
|
|
|
|
}
|
2021-10-05 12:18:58 +00:00
|
|
|
|
|
|
|
|
|
public async void QueryStats()
|
|
|
|
|
{
|
|
|
|
|
Dictionary<string, string> response = await SafelySendCommandAsync(new StatsCommand());
|
|
|
|
|
|
|
|
|
|
_stats.Songs = int.Parse(response["songs"]);
|
|
|
|
|
_stats.Albums = int.Parse(response["albums"]);
|
|
|
|
|
_stats.Artists = int.Parse(response["artists"]);
|
|
|
|
|
|
|
|
|
|
TimeSpan time;
|
|
|
|
|
time = TimeSpan.FromSeconds(int.Parse(response["uptime"]));
|
|
|
|
|
_stats.Uptime = time.ToString(@"dd\:hh\:mm\:ss");
|
|
|
|
|
time = TimeSpan.FromSeconds(int.Parse(response["db_playtime"]));
|
|
|
|
|
_stats.TotalPlaytime = time.ToString(@"dd\:hh\:mm\:ss");
|
|
|
|
|
time = TimeSpan.FromSeconds(int.Parse(response["playtime"]));
|
|
|
|
|
_stats.TotalTimePlayed = time.ToString(@"dd\:hh\:mm\:ss");
|
|
|
|
|
|
|
|
|
|
DateTime date = new DateTime(1970, 1, 1).AddSeconds(int.Parse(response["db_update"])).ToLocalTime();
|
2021-10-05 16:54:49 +00:00
|
|
|
|
_stats.DatabaseUpdate = date.ToString("dd/MM/yyyy @ HH:mm");
|
2021-10-05 12:18:58 +00:00
|
|
|
|
}
|
2021-08-13 23:20:38 +00:00
|
|
|
|
}
|
2021-09-01 00:35:37 +00:00
|
|
|
|
}
|