Compare commits
4 Commits
e0d640532c
...
4c71d6a6e0
Author | SHA1 | Date | |
---|---|---|---|
4c71d6a6e0 | |||
3685c369b4 | |||
9bd088fac8 | |||
0be28ab205 |
@ -20,6 +20,17 @@ using MpcNET.Types;
|
|||||||
|
|
||||||
namespace unison
|
namespace unison
|
||||||
{
|
{
|
||||||
|
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; }
|
||||||
|
}
|
||||||
|
|
||||||
public class MPDHandler
|
public class MPDHandler
|
||||||
{
|
{
|
||||||
private bool _connected;
|
private bool _connected;
|
||||||
@ -36,6 +47,7 @@ namespace unison
|
|||||||
private MpdStatus _currentStatus;
|
private MpdStatus _currentStatus;
|
||||||
private IMpdFile _currentSong;
|
private IMpdFile _currentSong;
|
||||||
private BitmapFrame _cover;
|
private BitmapFrame _cover;
|
||||||
|
public Statistics _stats;
|
||||||
private readonly System.Timers.Timer _elapsedTimer;
|
private readonly System.Timers.Timer _elapsedTimer;
|
||||||
private DispatcherTimer _retryTimer;
|
private DispatcherTimer _retryTimer;
|
||||||
|
|
||||||
@ -58,6 +70,8 @@ namespace unison
|
|||||||
|
|
||||||
Initialize(null, null);
|
Initialize(null, null);
|
||||||
|
|
||||||
|
_stats = new Statistics();
|
||||||
|
|
||||||
_retryTimer = new DispatcherTimer();
|
_retryTimer = new DispatcherTimer();
|
||||||
_retryTimer.Interval = TimeSpan.FromSeconds(5);
|
_retryTimer.Interval = TimeSpan.FromSeconds(5);
|
||||||
_retryTimer.Tick += Initialize;
|
_retryTimer.Tick += Initialize;
|
||||||
@ -417,6 +431,7 @@ namespace unison
|
|||||||
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 Statistics GetStats() => _stats;
|
||||||
public double GetCurrentTime() => _currentTime;
|
public double GetCurrentTime() => _currentTime;
|
||||||
|
|
||||||
public bool IsConnected() => _connected;
|
public bool IsConnected() => _connected;
|
||||||
@ -479,5 +494,25 @@ namespace unison
|
|||||||
CommandList commandList = new CommandList(new IMpcCommand<object>[] { new ClearCommand(), new AddCommand(Uri), new PlayCommand(0) });
|
CommandList commandList = new CommandList(new IMpcCommand<object>[] { new ClearCommand(), new AddCommand(Uri), new PlayCommand(0) });
|
||||||
SendCommand(commandList);
|
SendCommand(commandList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
_stats.DatabaseUpdate = date.ToString("dd/MM/yyyy @ HH:mm");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
72
Resources/Resources.Designer.cs
generated
72
Resources/Resources.Designer.cs
generated
@ -501,6 +501,78 @@ namespace unison.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Stats.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Albums:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_Albums {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_Albums", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Artists:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_Artists {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_Artists", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Last database update:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_LastDatabaseUpdate {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_LastDatabaseUpdate", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Songs:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_Songs {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_Songs", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Total playtime:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_TotalPlaytime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_TotalPlaytime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Total time played:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_TotalTimePlayed {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_TotalTimePlayed", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to MPD uptime:.
|
||||||
|
/// </summary>
|
||||||
|
public static string Stats_Uptime {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Stats_Uptime", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Stop Snapcast.
|
/// Looks up a localized string similar to Stop Snapcast.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -264,6 +264,30 @@
|
|||||||
<data name="StartSnapcast" xml:space="preserve">
|
<data name="StartSnapcast" xml:space="preserve">
|
||||||
<value>Démarrer Snapcast</value>
|
<value>Démarrer Snapcast</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Stats" xml:space="preserve">
|
||||||
|
<value>Stats</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Albums" xml:space="preserve">
|
||||||
|
<value>Albums :</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Artists" xml:space="preserve">
|
||||||
|
<value>Artistes :</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_LastDatabaseUpdate" xml:space="preserve">
|
||||||
|
<value>Mise à jour de la base de données :</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Songs" xml:space="preserve">
|
||||||
|
<value>Morceaux :</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_TotalPlaytime" xml:space="preserve">
|
||||||
|
<value>Temps total :</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_TotalTimePlayed" xml:space="preserve">
|
||||||
|
<value>Temps d'écoute écoulé :</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Uptime" xml:space="preserve">
|
||||||
|
<value>MPD lancé depuis : </value>
|
||||||
|
</data>
|
||||||
<data name="StopSnapcast" xml:space="preserve">
|
<data name="StopSnapcast" xml:space="preserve">
|
||||||
<value>Stopper Snapcast</value>
|
<value>Stopper Snapcast</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -264,6 +264,30 @@
|
|||||||
<data name="StartSnapcast" xml:space="preserve">
|
<data name="StartSnapcast" xml:space="preserve">
|
||||||
<value>Start Snapcast</value>
|
<value>Start Snapcast</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Stats" xml:space="preserve">
|
||||||
|
<value>Stats</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Albums" xml:space="preserve">
|
||||||
|
<value>Albums:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Artists" xml:space="preserve">
|
||||||
|
<value>Artists:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_LastDatabaseUpdate" xml:space="preserve">
|
||||||
|
<value>Last database update:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Songs" xml:space="preserve">
|
||||||
|
<value>Songs:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_TotalPlaytime" xml:space="preserve">
|
||||||
|
<value>Total playtime:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_TotalTimePlayed" xml:space="preserve">
|
||||||
|
<value>Total time played:</value>
|
||||||
|
</data>
|
||||||
|
<data name="Stats_Uptime" xml:space="preserve">
|
||||||
|
<value>MPD uptime:</value>
|
||||||
|
</data>
|
||||||
<data name="StopSnapcast" xml:space="preserve">
|
<data name="StopSnapcast" xml:space="preserve">
|
||||||
<value>Stop Snapcast</value>
|
<value>Stop Snapcast</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -6,6 +6,8 @@ using System.Windows.Threading;
|
|||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Controls.Primitives;
|
using System.Windows.Controls.Primitives;
|
||||||
|
using MpcNET.Commands.Queue;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace unison
|
namespace unison
|
||||||
{
|
{
|
||||||
@ -61,9 +63,11 @@ namespace unison
|
|||||||
}
|
}
|
||||||
_settingsWin.UpdateConnectionStatus();
|
_settingsWin.UpdateConnectionStatus();
|
||||||
Connection.Text = $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
Connection.Text = $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
||||||
|
|
||||||
|
_shuffleWin.ListGenre();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnSongChanged(object sender, EventArgs e)
|
public async void OnSongChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (_mpd.GetCurrentSong() == null)
|
if (_mpd.GetCurrentSong() == null)
|
||||||
return;
|
return;
|
||||||
@ -109,6 +113,32 @@ namespace unison
|
|||||||
_timer.Start();
|
_timer.Start();
|
||||||
EndTime.Text = FormatSeconds(_mpd.GetCurrentSong().Time);
|
EndTime.Text = FormatSeconds(_mpd.GetCurrentSong().Time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug.WriteLine("Song changed called!");
|
||||||
|
|
||||||
|
// handle continuous shuffle
|
||||||
|
if (_shuffleWin.GetContinuous())
|
||||||
|
{
|
||||||
|
System.Collections.Generic.IEnumerable<MpcNET.Types.IMpdFile> a = await _mpd.SafelySendCommandAsync(new PlaylistCommand());
|
||||||
|
int queueSize = 0;
|
||||||
|
foreach (var i in a)
|
||||||
|
{
|
||||||
|
Debug.WriteLine(i.Path);
|
||||||
|
queueSize++;
|
||||||
|
}
|
||||||
|
Debug.WriteLine("queue size is: " + queueSize);
|
||||||
|
|
||||||
|
if (queueSize < 5)
|
||||||
|
{
|
||||||
|
_shuffleWin.AddContinuousSongs();
|
||||||
|
}
|
||||||
|
|
||||||
|
// query queue
|
||||||
|
// if (queue.SongRemaining < 5)
|
||||||
|
//{
|
||||||
|
// // query shuffle songs
|
||||||
|
//}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnStatusChanged(object sender, EventArgs e)
|
public void OnStatusChanged(object sender, EventArgs e)
|
||||||
@ -137,6 +167,9 @@ namespace unison
|
|||||||
DefaultState();
|
DefaultState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_mpd.QueryStats();
|
||||||
|
_settingsWin.UpdateStats();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DefaultState(bool LostConnection = false)
|
private void DefaultState(bool LostConnection = false)
|
||||||
|
@ -14,12 +14,10 @@
|
|||||||
<DockPanel Margin="8">
|
<DockPanel Margin="8">
|
||||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
<GroupBox.Header>
|
<GroupBox.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
<emoji:EmojiInline Text="📶"/>
|
<emoji:EmojiInline Text="📶"/>
|
||||||
<Run Text="{x:Static properties:Resources.Settings_Connection}"/>
|
<Run Text="{x:Static properties:Resources.Settings_Connection}"/>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
|
||||||
</GroupBox.Header>
|
</GroupBox.Header>
|
||||||
<Grid VerticalAlignment="Top">
|
<Grid VerticalAlignment="Top">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
@ -46,53 +44,20 @@
|
|||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
<TabItem Header="Snapcast">
|
|
||||||
<DockPanel Margin="8">
|
|
||||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
|
||||||
<GroupBox.Header>
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<emoji:TextBlock Text="🔊 Snapcast"/>
|
|
||||||
</StackPanel>
|
|
||||||
</GroupBox.Header>
|
|
||||||
<Grid VerticalAlignment="Top">
|
|
||||||
<StackPanel>
|
|
||||||
<StackPanel>
|
|
||||||
<CheckBox x:Name="SnapcastStartup" Margin="5, 5, 0, 0">
|
|
||||||
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastLauch}" TextWrapping="Wrap"/>
|
|
||||||
</CheckBox>
|
|
||||||
<CheckBox x:Name="SnapcastWindow" Margin="5,2.5,0,0">
|
|
||||||
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastWindow}" TextWrapping="Wrap"/>
|
|
||||||
</CheckBox>
|
|
||||||
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastPort}" TextWrapping="Wrap" Margin="5,5,0,0"/>
|
|
||||||
<TextBox x:Name="SnapcastPort" MaxLength="5" PreviewTextInput="NumberValidationTextBox" TextWrapping="Wrap" Width="250" Margin="10,2,5,0" HorizontalAlignment="Left"/>
|
|
||||||
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastPath}" TextWrapping="Wrap" Margin="5,5,0,0"/>
|
|
||||||
<TextBox x:Name="SnapcastPath" TextWrapping="Wrap" Width="250" Margin="10,2,5,0" HorizontalAlignment="Left"/>
|
|
||||||
<TextBlock TextWrapping="Wrap" Margin="5,5,0,0" TextAlignment="Left" Width="250">
|
|
||||||
<Run Text="{x:Static properties:Resources.Settings_SnapcastInfo1}" /><Run Text="{x:Static properties:Resources.Settings_SnapcastInfo2}" FontStyle="Italic" FontWeight="DemiBold" /><Run Text="{x:Static properties:Resources.Settings_SnapcastInfo3}" />
|
|
||||||
</TextBlock>
|
|
||||||
<Button Content="{x:Static properties:Resources.Settings_SnapcastResetButton}" Margin="0,10,0,0" Width="120" Click="SnapcastReset_Clicked"/>
|
|
||||||
</StackPanel>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</GroupBox>
|
|
||||||
</DockPanel>
|
|
||||||
</TabItem>
|
|
||||||
|
|
||||||
<TabItem Header="{x:Static properties:Resources.Settings_Shortcuts}">
|
<TabItem Header="{x:Static properties:Resources.Settings_Shortcuts}">
|
||||||
<DockPanel Margin="8">
|
<DockPanel Margin="8">
|
||||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
<GroupBox.Header>
|
<GroupBox.Header>
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
<emoji:EmojiInline Text="⌨️ "/>
|
<emoji:EmojiInline Text="⌨️ "/>
|
||||||
<Run Text="{x:Static properties:Resources.Settings_Shortcuts}"></Run>
|
<Run Text="{x:Static properties:Resources.Settings_Shortcuts}"></Run>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
|
||||||
</GroupBox.Header>
|
</GroupBox.Header>
|
||||||
<Grid>
|
<Grid>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeOffset}" TextWrapping="Wrap"/>
|
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeOffset}" TextWrapping="Wrap" Margin="0,2,0,0"/>
|
||||||
<TextBox x:Name="VolumeOffset" TextWrapping="Wrap" Width="25" PreviewTextInput="NumberValidationTextBox" Margin="8,2,0,0"/>
|
<TextBox x:Name="VolumeOffset" TextWrapping="Wrap" Width="25" PreviewTextInput="NumberValidationTextBox" Margin="8,2,0,0"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<Grid MinWidth="300" Margin="0,5,0,0">
|
<Grid MinWidth="300" Margin="0,5,0,0">
|
||||||
@ -131,6 +96,87 @@
|
|||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="Snapcast">
|
||||||
|
<DockPanel Margin="8">
|
||||||
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<emoji:TextBlock Text="🔊 Snapcast"/>
|
||||||
|
</GroupBox.Header>
|
||||||
|
<Grid VerticalAlignment="Top">
|
||||||
|
<StackPanel>
|
||||||
|
<StackPanel>
|
||||||
|
<CheckBox x:Name="SnapcastStartup" Margin="5, 5, 0, 0">
|
||||||
|
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastLauch}" TextWrapping="Wrap"/>
|
||||||
|
</CheckBox>
|
||||||
|
<CheckBox x:Name="SnapcastWindow" Margin="5,2.5,0,0">
|
||||||
|
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastWindow}" TextWrapping="Wrap"/>
|
||||||
|
</CheckBox>
|
||||||
|
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastPort}" TextWrapping="Wrap" Margin="5,5,0,0"/>
|
||||||
|
<TextBox x:Name="SnapcastPort" MaxLength="5" PreviewTextInput="NumberValidationTextBox" TextWrapping="Wrap" Width="250" Margin="10,2,5,0" HorizontalAlignment="Left"/>
|
||||||
|
<TextBlock Text="{x:Static properties:Resources.Settings_SnapcastPath}" TextWrapping="Wrap" Margin="5,5,0,0"/>
|
||||||
|
<TextBox x:Name="SnapcastPath" TextWrapping="Wrap" Width="250" Margin="10,2,5,0" HorizontalAlignment="Left"/>
|
||||||
|
<TextBlock TextWrapping="Wrap" Margin="5,5,0,0" TextAlignment="Left" Width="250">
|
||||||
|
<Run Text="{x:Static properties:Resources.Settings_SnapcastInfo1}" /><Run Text="{x:Static properties:Resources.Settings_SnapcastInfo2}" FontStyle="Italic" FontWeight="DemiBold" /><Run Text="{x:Static properties:Resources.Settings_SnapcastInfo3}" />
|
||||||
|
</TextBlock>
|
||||||
|
<Button Content="{x:Static properties:Resources.Settings_SnapcastResetButton}" Margin="0,10,0,0" Width="120" Click="SnapcastReset_Clicked"/>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
</DockPanel>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="Shuffle">
|
||||||
|
<DockPanel Margin="8">
|
||||||
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<TextBlock>
|
||||||
|
<emoji:EmojiInline Text="🔁 "/>
|
||||||
|
<Run Text="Shuffle"></Run>
|
||||||
|
</TextBlock>
|
||||||
|
</GroupBox.Header>
|
||||||
|
<Grid MaxWidth="500">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock TextWrapping="Wrap">
|
||||||
|
<Run>The shuffle window allows to add random songs to your queue. Both options take into account the filter.</Run>
|
||||||
|
<Run>If the filter is empty, the entire music library is taken into account.</Run><LineBreak/><LineBreak/>
|
||||||
|
<Run FontWeight="Bold">Continuous shuffle</Run><LineBreak/>
|
||||||
|
<Run>By enabling this option, unison will automatically add songs to the queue so you never run out of songs to listen to.</Run>
|
||||||
|
<LineBreak/><LineBreak/>
|
||||||
|
|
||||||
|
<Run FontWeight="Bold">Add to queue</Run><LineBreak/>
|
||||||
|
<Run>Add a fixed number of songs to the queue. It can take a long time to add more than 100 songs, so the option is limited to 1000 songs.</Run>
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
</DockPanel>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
|
<TabItem Header="{x:Static properties:Resources.Stats}">
|
||||||
|
<DockPanel Margin="8">
|
||||||
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<TextBlock>
|
||||||
|
<emoji:EmojiInline Text="📊"/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats}"/>
|
||||||
|
</TextBlock>
|
||||||
|
</GroupBox.Header>
|
||||||
|
<Grid VerticalAlignment="Top">
|
||||||
|
<TextBlock>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_Songs}"/><Run Text=" "/><Run x:Name="StatSong"/><LineBreak/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_Albums}"/><Run Text=" "/><Run x:Name="StatAlbum"/><LineBreak/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_Artists}"/><Run Text=" "/><Run x:Name="StatArtist"/><LineBreak/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_TotalPlaytime}"/><Run Text=" "/><Run x:Name="StatTotalPlaytime"/><LineBreak/><LineBreak/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_Uptime}"/><Run Text=" "/><Run x:Name="StatUptime"/><LineBreak/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_TotalTimePlayed}"/><Run Text=" "/><Run x:Name="StatTotalTimePlayed"/><LineBreak/>
|
||||||
|
<Run Text="{x:Static properties:Resources.Stats_LastDatabaseUpdate}"/><Run Text=" "/><Run x:Name="StatDatabaseUpdate"/>
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
</GroupBox>
|
||||||
|
</DockPanel>
|
||||||
|
</TabItem>
|
||||||
|
|
||||||
<TabItem Header="{x:Static properties:Resources.Settings_About}" Height="20" VerticalAlignment="Bottom">
|
<TabItem Header="{x:Static properties:Resources.Settings_About}" Height="20" VerticalAlignment="Bottom">
|
||||||
<DockPanel Margin="8">
|
<DockPanel Margin="8">
|
||||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
|
@ -88,6 +88,18 @@ namespace unison
|
|||||||
SnapcastPort.Text = (string)Application.Current.FindResource("snapcastPort");
|
SnapcastPort.Text = (string)Application.Current.FindResource("snapcastPort");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateStats()
|
||||||
|
{
|
||||||
|
MPDHandler mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
|
StatSong.Text = mpd.GetStats().Songs.ToString();
|
||||||
|
StatAlbum.Text = mpd.GetStats().Albums.ToString();
|
||||||
|
StatArtist.Text = mpd.GetStats().Artists.ToString();
|
||||||
|
StatTotalPlaytime.Text = mpd.GetStats().TotalPlaytime.ToString();
|
||||||
|
StatUptime.Text = mpd.GetStats().Uptime.ToString();
|
||||||
|
StatTotalTimePlayed.Text = mpd.GetStats().TotalTimePlayed.ToString();
|
||||||
|
StatDatabaseUpdate.Text = mpd.GetStats().DatabaseUpdate.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
public void SaveSettings()
|
public void SaveSettings()
|
||||||
{
|
{
|
||||||
Properties.Settings.Default.mpd_host = MpdHost.Text;
|
Properties.Settings.Default.mpd_host = MpdHost.Text;
|
||||||
|
@ -14,8 +14,8 @@
|
|||||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||||
<GroupBox.Header>
|
<GroupBox.Header>
|
||||||
<TextBlock>
|
<TextBlock>
|
||||||
<emoji:EmojiInline Text="🔁"/>
|
<emoji:EmojiInline Text="🔡"/>
|
||||||
<Run Text="Shuffle"/>
|
<Run Text="Filter"/>
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</GroupBox.Header>
|
</GroupBox.Header>
|
||||||
<StackPanel Orientation="Vertical" Margin="5,0,5,0">
|
<StackPanel Orientation="Vertical" Margin="5,0,5,0">
|
||||||
@ -41,20 +41,52 @@
|
|||||||
<TextBox x:Name="Year" Width="240"/>
|
<TextBox x:Name="Year" Width="240"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
|
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
|
||||||
<StackPanel Orientation="Vertical">
|
<StackPanel Orientation="Vertical">
|
||||||
<TextBlock Text="Genre" Margin="0,0,0,2"/>
|
<TextBlock Text="Genre" Margin="0,0,0,2"/>
|
||||||
<ComboBox x:Name="Genre" SelectedIndex="0" Width="240" ScrollViewer.CanContentScroll="False"/>
|
<ComboBox x:Name="Genre" SelectedIndex="0" Width="240" ScrollViewer.CanContentScroll="False"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<Button Content="Reset" Click="Reset_Clicked" Padding="5, 2" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="20,0,0,0" FocusVisualStyle="{x:Null}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<StackPanel x:Name="SongFilterPanel" Margin="0,5,0,0" Visibility="Collapsed">
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,8,0,0">
|
<TextBlock>
|
||||||
<TextBlock Text="Number of songs to add" Margin="0,0,0,5"/>
|
<Run Text="Number of songs in filter: "/><Run x:Name="SongFilterNumber" FontWeight="Bold"/>
|
||||||
<TextBox x:Name="SongNumber" Text="100" Width="45" Margin="5,0,0,0"/>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
|
<GroupBox Margin="0,5,0,0" HorizontalAlignment="Stretch">
|
||||||
<Button Content="Add to queue" Click="AddToQueue_Clicked" Padding="5, 2"/>
|
<GroupBox.Header>
|
||||||
|
<TextBlock>
|
||||||
|
<emoji:EmojiInline Text="♾️"/>
|
||||||
|
<Run Text="Continuous shuffle"/>
|
||||||
|
</TextBlock>
|
||||||
|
</GroupBox.Header>
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="5,8,0,0">
|
||||||
|
<CheckBox x:Name="ContinuousShuffle" Checked="ContinuousShuffle_Checked" Unchecked="ContinuousShuffle_Checked">
|
||||||
|
<TextBlock Text="Enable continuous shuffle" TextWrapping="Wrap"/>
|
||||||
|
</CheckBox>
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox x:Name="AddToQueueGroup" Margin="0,5,0,0" HorizontalAlignment="Stretch">
|
||||||
|
<GroupBox.Header>
|
||||||
|
<TextBlock>
|
||||||
|
<emoji:EmojiInline Text="➕"/>
|
||||||
|
<Run Text="Add to queue"/>
|
||||||
|
</TextBlock>
|
||||||
|
</GroupBox.Header>
|
||||||
|
<StackPanel Margin="5,0,0,0">
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,10,0,0">
|
||||||
|
<TextBox x:Name="SongNumber" Text="100" Width="35" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||||
|
<TextBlock Text="Number of songs to add" Margin="5,0,0,5"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
|
||||||
|
<Button Content="Add to queue" Click="AddToQueue_Clicked" Padding="5, 2" HorizontalAlignment="Left" FocusVisualStyle="{x:Null}"/>
|
||||||
|
<TextBlock x:Name="SearchStatus" Margin="15,3,0,0" FontStyle="Italic" Visibility="Collapsed">
|
||||||
|
<Run Text="Added "/><Run x:Name="NumberAddedSongs"/><Run Text=" songs to the queue..."/>
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
@ -1,16 +1,71 @@
|
|||||||
using System.ComponentModel;
|
using MpcNET;
|
||||||
|
using MpcNET.Commands.Database;
|
||||||
|
using MpcNET.Commands.Reflection;
|
||||||
|
using MpcNET.Tags;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Interop;
|
using System.Windows.Interop;
|
||||||
|
|
||||||
|
// https://mpd.readthedocs.io/en/stable/protocol.html#binary
|
||||||
|
|
||||||
namespace unison
|
namespace unison
|
||||||
{
|
{
|
||||||
public partial class Shuffle : Window
|
public partial class Shuffle : Window
|
||||||
{
|
{
|
||||||
//private MPDHandler _mpd;
|
private MPDHandler _mpd;
|
||||||
|
bool _continuous = false;
|
||||||
|
List<string> _songList { get; }
|
||||||
|
|
||||||
public Shuffle()
|
public Shuffle()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_songList = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool GetContinuous()
|
||||||
|
{
|
||||||
|
return _continuous;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddContinuousSongs()
|
||||||
|
{
|
||||||
|
int AddedSongs = 0;
|
||||||
|
NumberAddedSongs.Text = AddedSongs.ToString();
|
||||||
|
SearchStatus.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
HashSet<int> SongIndex = new();
|
||||||
|
while (SongIndex.Count < 2)
|
||||||
|
{
|
||||||
|
int MaxIndex = new Random().Next(0, _songList.Count - 1);
|
||||||
|
SongIndex.Add(MaxIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (int index in SongIndex)
|
||||||
|
_mpd.AddSong(_songList[index]);
|
||||||
|
|
||||||
|
SearchStatus.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ListGenre()
|
||||||
|
{
|
||||||
|
if (Genre.Items.Count == 0)
|
||||||
|
{
|
||||||
|
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
|
Genre.Items.Add("");
|
||||||
|
List<string> Response = await _mpd.SafelySendCommandAsync(new ListCommand(MpdTags.Genre, null, null));
|
||||||
|
foreach (var genre in Response)
|
||||||
|
Genre.Items.Add(genre);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async void ListFolder()
|
||||||
|
{
|
||||||
|
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
|
//await _mpd.SafelySendCommandAsync(new )
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Window_Closing(object sender, CancelEventArgs e)
|
private void Window_Closing(object sender, CancelEventArgs e)
|
||||||
@ -26,9 +81,156 @@ namespace unison
|
|||||||
helper.EnsureHandle();
|
helper.EnsureHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddToQueue_Clicked(object sender, RoutedEventArgs e)
|
private void Reset_Clicked(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
|
Song.Text = "";
|
||||||
|
Artist.Text = "";
|
||||||
|
Album.Text = "";
|
||||||
|
Year.Text = "";
|
||||||
|
Genre.SelectedIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ContinuousShuffle_Checked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ContinuousShuffle.IsChecked == true)
|
||||||
|
{
|
||||||
|
AddToQueueGroup.IsEnabled = false;
|
||||||
|
_continuous = true;
|
||||||
|
_songList.Clear();
|
||||||
|
await GetSongsFromFilter();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddToQueueGroup.IsEnabled = true;
|
||||||
|
_continuous = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// search "((title contains ''))" window 38669:38670
|
||||||
|
// listfiles
|
||||||
|
|
||||||
|
private async void AddToQueueRandom()
|
||||||
|
{
|
||||||
|
int AddedSongs = 0;
|
||||||
|
NumberAddedSongs.Text = AddedSongs.ToString();
|
||||||
|
SearchStatus.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
for (int i = 0; i < int.Parse(SongNumber.Text); i++)
|
||||||
|
{
|
||||||
|
// generate random number
|
||||||
|
int song = new Random().Next(0, _mpd.GetStats().Songs - 1);
|
||||||
|
|
||||||
|
// query random song
|
||||||
|
CommandList commandList = new CommandList(new IMpcCommand<object>[] { new SearchCommand(MpdTags.Title, "", song, song + 1) });
|
||||||
|
string Response = await _mpd.SafelySendCommandAsync(commandList);
|
||||||
|
|
||||||
|
await Task.Delay(1);
|
||||||
|
if (Response.Length > 0)
|
||||||
|
{
|
||||||
|
// parse song and add it to queue
|
||||||
|
int start = Response.IndexOf("[file, ");
|
||||||
|
int end = Response.IndexOf("],");
|
||||||
|
string filePath = Response.Substring(start + 7, end - (start + 7));
|
||||||
|
_mpd.AddSong(filePath);
|
||||||
|
|
||||||
|
AddedSongs++;
|
||||||
|
NumberAddedSongs.Text = AddedSongs.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchStatus.Visibility = Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task GetSongsFromFilter()
|
||||||
|
{
|
||||||
|
_songList.Clear();
|
||||||
|
|
||||||
|
int song = _mpd.GetStats().Songs;
|
||||||
|
|
||||||
|
List<KeyValuePair<ITag, string>> filters = new();
|
||||||
|
filters.Add(new KeyValuePair<ITag, string>(MpdTags.Title, Song.Text));
|
||||||
|
filters.Add(new KeyValuePair<ITag, string>(MpdTags.Artist, Artist.Text));
|
||||||
|
filters.Add(new KeyValuePair<ITag, string>(MpdTags.Album, Album.Text));
|
||||||
|
filters.Add(new KeyValuePair<ITag, string>(MpdTags.Date, Year.Text));
|
||||||
|
filters.Add(new KeyValuePair<ITag, string>(MpdTags.Genre, Genre.Text));
|
||||||
|
|
||||||
|
CommandList commandList = new CommandList(new IMpcCommand<object>[] { new SearchCommand(filters, 0, song + 1) });
|
||||||
|
string Response = await _mpd.SafelySendCommandAsync(commandList);
|
||||||
|
|
||||||
|
// create a list of the file url
|
||||||
|
string[] value = Response.Split(", [file, ");
|
||||||
|
|
||||||
|
foreach (string file in value)
|
||||||
|
{
|
||||||
|
int start = 0;
|
||||||
|
int end = file.IndexOf("],");
|
||||||
|
string filePath = file.Substring(start, end - start);
|
||||||
|
|
||||||
|
_songList.Add(filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove characters from first file
|
||||||
|
_songList[0] = _songList[0].Substring(7, _songList[0].Length - 7);
|
||||||
|
|
||||||
|
SongFilterPanel.Visibility = Visibility.Visible;
|
||||||
|
SongFilterNumber.Text = _songList.Count.ToString();
|
||||||
|
|
||||||
|
// DEBUG
|
||||||
|
foreach (var a in _songList)
|
||||||
|
Debug.WriteLine(a);
|
||||||
|
Debug.WriteLine("number of songs found: " + _songList.Count);
|
||||||
|
Debug.WriteLine("number of songs requested: " + int.Parse(SongNumber.Text));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void AddToQueueFilter()
|
||||||
|
{
|
||||||
|
await GetSongsFromFilter();
|
||||||
|
|
||||||
|
int AddedSongs = 0;
|
||||||
|
NumberAddedSongs.Text = AddedSongs.ToString();
|
||||||
|
SearchStatus.Visibility = Visibility.Visible;
|
||||||
|
|
||||||
|
// more requested songs than available => add everything
|
||||||
|
if (int.Parse(SongNumber.Text) > _songList.Count)
|
||||||
|
{
|
||||||
|
foreach (string path in _songList)
|
||||||
|
{
|
||||||
|
await Task.Delay(1);
|
||||||
|
_mpd.AddSong(path);
|
||||||
|
|
||||||
|
AddedSongs++;
|
||||||
|
NumberAddedSongs.Text = AddedSongs.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// more available songs than requested =>
|
||||||
|
// we add unique indexes until we reach the requested amount
|
||||||
|
else
|
||||||
|
{
|
||||||
|
HashSet<int> SongIndex = new();
|
||||||
|
while (SongIndex.Count < int.Parse(SongNumber.Text))
|
||||||
|
{
|
||||||
|
int MaxIndex = new Random().Next(0, _songList.Count - 1);
|
||||||
|
SongIndex.Add(MaxIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (int index in SongIndex)
|
||||||
|
_mpd.AddSong(_songList[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchStatus.Visibility = Visibility.Collapsed;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddToQueue_Clicked(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||||
|
if (_mpd.GetStats() == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Song.Text.Length == 0 && Artist.Text.Length == 0 && Album.Text.Length == 0 && Year.Text.Length == 0 && Genre.SelectedIndex == 0)
|
||||||
|
AddToQueueRandom();
|
||||||
|
else
|
||||||
|
AddToQueueFilter();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user