Compare commits
5 Commits
v1.3
...
c93a9a326e
Author | SHA1 | Date | |
---|---|---|---|
c93a9a326e | |||
c055c59de7 | |||
4c71d6a6e0 | |||
3685c369b4 | |||
e0d640532c |
@ -497,21 +497,23 @@ namespace unison
|
||||
|
||||
public async void QueryStats()
|
||||
{
|
||||
Dictionary<string, string> response = await SafelySendCommandAsync(new StatsCommand());
|
||||
Dictionary<string, string> Response = await SafelySendCommandAsync(new StatsCommand());
|
||||
if (Response == null)
|
||||
return;
|
||||
|
||||
_stats.Songs = int.Parse(response["songs"]);
|
||||
_stats.Albums = int.Parse(response["albums"]);
|
||||
_stats.Artists = int.Parse(response["artists"]);
|
||||
_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"]));
|
||||
time = TimeSpan.FromSeconds(int.Parse(Response["uptime"]));
|
||||
_stats.Uptime = time.ToString(@"dd\:hh\:mm\:ss");
|
||||
time = TimeSpan.FromSeconds(int.Parse(response["db_playtime"]));
|
||||
time = TimeSpan.FromSeconds(int.Parse(Response["db_playtime"]));
|
||||
_stats.TotalPlaytime = time.ToString(@"dd\:hh\:mm\:ss");
|
||||
time = TimeSpan.FromSeconds(int.Parse(response["playtime"]));
|
||||
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();
|
||||
DateTime date = new DateTime(1970, 1, 1).AddSeconds(int.Parse(Response["db_update"])).ToLocalTime();
|
||||
_stats.DatabaseUpdate = date.ToString("dd/MM/yyyy @ HH:mm");
|
||||
}
|
||||
}
|
||||
|
@ -135,12 +135,12 @@
|
||||
<TextBlock x:Name="Connection" HorizontalAlignment="Center" Text="Not connected" TextWrapping="Wrap" VerticalAlignment="Top" TextAlignment="Center" Foreground="{DynamicResource {x:Static SystemColors.ControlDarkDarkBrushKey}}" Margin="5,0,0,0" />
|
||||
</StackPanel>
|
||||
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,10,0">
|
||||
<!--<Button x:Name="Shuffle" Padding="5, 2" HorizontalAlignment="Right" Margin="0,0,10,0" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
|
||||
<Button x:Name="Shuffle" Padding="5, 2" Click="Shuffle_Clicked" Margin="0,0,10,0" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<emoji:TextBlock Text="🔁" Padding="0,0,0,2"/>
|
||||
<TextBlock Text="Shuffle" Margin="5, 0, 0, 0"/>
|
||||
</StackPanel>
|
||||
</Button>-->
|
||||
</Button>
|
||||
<Button x:Name="Settings" Padding="5, 2" Click="Settings_Clicked" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<emoji:TextBlock Text="🛠️" Padding="0,0,0,2"/>
|
||||
|
@ -6,6 +6,8 @@ using System.Windows.Threading;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using MpcNET.Commands.Queue;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace unison
|
||||
{
|
||||
@ -13,6 +15,7 @@ namespace unison
|
||||
{
|
||||
private readonly Settings _settingsWin;
|
||||
private readonly Radios _radiosWin;
|
||||
private readonly Shuffle _shuffleWin;
|
||||
private readonly DispatcherTimer _timer;
|
||||
private readonly MPDHandler _mpd;
|
||||
|
||||
@ -25,6 +28,7 @@ namespace unison
|
||||
|
||||
_settingsWin = new Settings();
|
||||
_radiosWin = new Radios();
|
||||
_shuffleWin = new Shuffle();
|
||||
_timer = new DispatcherTimer();
|
||||
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
|
||||
@ -59,9 +63,12 @@ namespace unison
|
||||
}
|
||||
_settingsWin.UpdateConnectionStatus();
|
||||
Connection.Text = $"{Properties.Settings.Default.mpd_host}:{Properties.Settings.Default.mpd_port}";
|
||||
|
||||
_shuffleWin.ListGenre();
|
||||
_shuffleWin.ListFolder();
|
||||
}
|
||||
|
||||
public void OnSongChanged(object sender, EventArgs e)
|
||||
public async void OnSongChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (_mpd.GetCurrentSong() == null)
|
||||
return;
|
||||
@ -107,6 +114,32 @@ namespace unison
|
||||
_timer.Start();
|
||||
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)
|
||||
@ -229,6 +262,15 @@ namespace unison
|
||||
_radiosWin.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
public void Shuffle_Clicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_shuffleWin.Show();
|
||||
_shuffleWin.Activate();
|
||||
|
||||
if (_shuffleWin.WindowState == WindowState.Minimized)
|
||||
_shuffleWin.WindowState = WindowState.Normal;
|
||||
}
|
||||
|
||||
public void Settings_Clicked(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_settingsWin.Show();
|
||||
|
@ -44,25 +44,53 @@
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static properties:Resources.Stats}">
|
||||
|
||||
<TabItem Header="{x:Static properties:Resources.Settings_Shortcuts}">
|
||||
<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}"/>
|
||||
<emoji:EmojiInline Text="⌨️ "/>
|
||||
<Run Text="{x:Static properties:Resources.Settings_Shortcuts}"></Run>
|
||||
</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>
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBox x:Name="VolumeOffset" TextWrapping="Wrap" Width="25" PreviewTextInput="NumberValidationTextBox" Margin="0,2,0,0"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeOffset}" TextWrapping="Wrap" Margin="5,2,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid MinWidth="300" Margin="0,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_NextTrack}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="0" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_PreviousTrack}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="1" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_PlayPause}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="2" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeUp}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="3" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeDown}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="4" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeMute}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="5" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_ShowWindow}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="6" Margin="1"/>
|
||||
|
||||
<TextBlock Text="ctrl + media_next" TextWrapping="Wrap" Grid.Column="1" Grid.Row="0" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + media_prev" TextWrapping="Wrap" Grid.Column="1" Grid.Row="1" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + media_play" TextWrapping="Wrap" Grid.Column="1" Grid.Row="2" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + volume_up" TextWrapping="Wrap" Grid.Column="1" Grid.Row="3" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + volume_down" TextWrapping="Wrap" Grid.Column="1" Grid.Row="4" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + volume_mute" TextWrapping="Wrap" Grid.Column="1" Grid.Row="5" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + alt + enter" TextWrapping="Wrap" Grid.Column="1" Grid.Row="6" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
</DockPanel>
|
||||
@ -98,57 +126,61 @@
|
||||
</DockPanel>
|
||||
</TabItem>
|
||||
|
||||
<TabItem Header="{x:Static properties:Resources.Settings_Shortcuts}">
|
||||
<TabItem Header="Shuffle">
|
||||
<DockPanel Margin="8">
|
||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||
<GroupBox.Header>
|
||||
<TextBlock>
|
||||
<emoji:EmojiInline Text="⌨️ "/>
|
||||
<Run Text="{x:Static properties:Resources.Settings_Shortcuts}"></Run>
|
||||
<emoji:EmojiInline Text="🔁 "/>
|
||||
<Run Text="Shuffle"></Run>
|
||||
</TextBlock>
|
||||
</GroupBox.Header>
|
||||
<Grid>
|
||||
<Grid MaxWidth="500">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<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 TextWrapping="Wrap" Width="25" PreviewTextInput="NumberValidationTextBox" Margin="0,2,0,0"/>
|
||||
<TextBlock Text="Prevent repetition rate (0-100%)" TextWrapping="Wrap" Margin="5,2,0,0"/>
|
||||
</StackPanel>
|
||||
<Grid MinWidth="300" Margin="0,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition/>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_NextTrack}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="0" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_PreviousTrack}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="1" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_PlayPause}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="2" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeUp}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="3" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeDown}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="4" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_VolumeMute}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="5" Margin="1"/>
|
||||
<TextBlock Text="{x:Static properties:Resources.Settings_ShowWindow}" TextWrapping="Wrap" Grid.Column="0" Grid.Row="6" Margin="1"/>
|
||||
<TextBlock TextWrapping="Wrap" Margin="0,10,0,0">
|
||||
<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/>
|
||||
|
||||
<TextBlock Text="ctrl + media_next" TextWrapping="Wrap" Grid.Column="1" Grid.Row="0" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + media_prev" TextWrapping="Wrap" Grid.Column="1" Grid.Row="1" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + media_play" TextWrapping="Wrap" Grid.Column="1" Grid.Row="2" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + volume_up" TextWrapping="Wrap" Grid.Column="1" Grid.Row="3" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + volume_down" TextWrapping="Wrap" Grid.Column="1" Grid.Row="4" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + volume_mute" TextWrapping="Wrap" Grid.Column="1" Grid.Row="5" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
<TextBlock Text="ctrl + alt + enter" TextWrapping="Wrap" Grid.Column="1" Grid.Row="6" Margin="1" HorizontalAlignment="Right" FontWeight="Bold"/>
|
||||
</Grid>
|
||||
<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">
|
||||
<DockPanel Margin="8">
|
||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||
|
102
Views/Shuffle.xaml
Normal file
102
Views/Shuffle.xaml
Normal file
@ -0,0 +1,102 @@
|
||||
<Window x:Class="unison.Shuffle"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
|
||||
xmlns:local="clr-namespace:unison"
|
||||
mc:Ignorable="d"
|
||||
Title="Shuffle" Closing="Window_Closing" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
|
||||
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<StackPanel HorizontalAlignment="Left" Orientation="Vertical" Margin="5,0,5,5">
|
||||
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
|
||||
<GroupBox.Header>
|
||||
<TextBlock>
|
||||
<emoji:EmojiInline Text="🔡"/>
|
||||
<Run Text="Filter"/>
|
||||
</TextBlock>
|
||||
</GroupBox.Header>
|
||||
<StackPanel Orientation="Vertical" Margin="5,0,5,0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Text="Song" Margin="0,0,0,2"/>
|
||||
<TextBox x:Name="Song" Width="240" Margin="5,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Vertical" Margin="20,0,0,0">
|
||||
<TextBlock Text="Artist" Margin="0,0,0,2"/>
|
||||
<TextBox x:Name="Artist" Width="240" Margin="5,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,0">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Text="Album" Margin="0,0,0,2"/>
|
||||
<TextBox x:Name="Album" Width="240" Margin="5,0,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Vertical" Margin="20,0,0,0">
|
||||
<TextBlock Text="Year" Margin="0,0,0,2"/>
|
||||
<TextBox x:Name="Year" Width="240" Margin="5,0,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<TextBlock Text="Genre" Margin="0,0,0,2"/>
|
||||
<ComboBox x:Name="Genre" SelectedIndex="0" Width="240" ScrollViewer.CanContentScroll="False" Margin="5,0,0,0"/>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Vertical" Margin="20,0,0,0">
|
||||
<TextBlock Text="Directory" Margin="0,0,0,2" TextDecorations="{x:Null}"/>
|
||||
<ComboBox x:Name="Directory" SelectedIndex="0" Width="240" ScrollViewer.CanContentScroll="False" Margin="5,0,0,0" IsEnabled="False"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,5,0,5">
|
||||
<Button Content="Reset" Click="Reset_Clicked" Padding="5, 2" VerticalAlignment="Bottom" HorizontalAlignment="Left" FocusVisualStyle="{x:Null}"/>
|
||||
</StackPanel>
|
||||
<StackPanel x:Name="SongFilterPanel" Margin="0,5,0,0" Visibility="Collapsed">
|
||||
<TextBlock>
|
||||
<Run Text="Number of songs in filter: "/><Run x:Name="SongFilterNumber" FontWeight="Bold"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Margin="0,5,0,0" HorizontalAlignment="Stretch">
|
||||
<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>
|
||||
</GroupBox>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
294
Views/Shuffle.xaml.cs
Normal file
294
Views/Shuffle.xaml.cs
Normal file
@ -0,0 +1,294 @@
|
||||
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.Interop;
|
||||
|
||||
namespace unison
|
||||
{
|
||||
public partial class Shuffle : Window
|
||||
{
|
||||
private MPDHandler _mpd;
|
||||
bool _continuous = false;
|
||||
List<string> _songList { get; }
|
||||
|
||||
public Shuffle()
|
||||
{
|
||||
InitializeComponent();
|
||||
_songList = new();
|
||||
}
|
||||
|
||||
public bool GetContinuous()
|
||||
{
|
||||
return _continuous;
|
||||
}
|
||||
|
||||
public void AddContinuousSongs()
|
||||
{
|
||||
if (Song.Text.Length == 0 && Artist.Text.Length == 0 && Album.Text.Length == 0 && Year.Text.Length == 0 && Genre.SelectedIndex == 0)
|
||||
{
|
||||
ContinuousShuffle_AddToQueueRandom();
|
||||
return;
|
||||
}
|
||||
|
||||
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"];
|
||||
List<string> Response = await _mpd.SafelySendCommandAsync(new ListCommand(MpdTags.Genre, null, null));
|
||||
|
||||
if (Response.Count > 0)
|
||||
{
|
||||
Genre.Items.Add("");
|
||||
foreach (var genre in Response)
|
||||
Genre.Items.Add(genre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async void ListFolder()
|
||||
{
|
||||
if (Directory.Items.Count == 0)
|
||||
{
|
||||
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
|
||||
List<string> Response = await _mpd.SafelySendCommandAsync(new ListFilesCommand());
|
||||
|
||||
if (Response.Count > 0)
|
||||
{
|
||||
Directory.Items.Add("");
|
||||
for (int i = 0; i < Response.Count; i++)
|
||||
if (i % 2 != 1)
|
||||
Directory.Items.Add(Response[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_Closing(object sender, CancelEventArgs e)
|
||||
{
|
||||
e.Cancel = true;
|
||||
WindowState = WindowState.Minimized;
|
||||
Hide();
|
||||
}
|
||||
|
||||
public void InitHwnd()
|
||||
{
|
||||
WindowInteropHelper helper = new(this);
|
||||
helper.EnsureHandle();
|
||||
}
|
||||
|
||||
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();
|
||||
if (Song.Text.Length == 0 && Artist.Text.Length == 0 && Album.Text.Length == 0 && Year.Text.Length == 0 && Genre.SelectedIndex == 0)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
/*await*/
|
||||
GetSongsFromFilter();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddToQueueGroup.IsEnabled = true;
|
||||
_continuous = false;
|
||||
}
|
||||
}
|
||||
|
||||
private async void ContinuousShuffle_AddToQueueRandom()
|
||||
{
|
||||
for (int i = 0; i < 2; 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);
|
||||
}
|
||||
}
|
||||
|
||||
SearchStatus.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
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();
|
||||
SongFilterPanel.Visibility = Visibility.Visible;
|
||||
|
||||
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, ");
|
||||
|
||||
// there are no song in this filter
|
||||
if (value[0] == "")
|
||||
{
|
||||
SongFilterNumber.Text = _songList.Count.ToString();
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (string file in value)
|
||||
{
|
||||
int start = 0;
|
||||
int end = file.IndexOf("],");
|
||||
string filePath = file.Substring(start, end - start);
|
||||
|
||||
_songList.Add(filePath);
|
||||
|
||||
SongFilterNumber.Text = _songList.Count.ToString();
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
@ -30,11 +30,11 @@
|
||||
<Image Width="16" Height="16" emoji:Image.Source="📻" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<!--<MenuItem Header="Shuffle" Command="{Binding Shuffle}">
|
||||
<MenuItem Header="Shuffle" Command="{Binding Shuffle}">
|
||||
<MenuItem.Icon>
|
||||
<Image Width="16" Height="16" emoji:Image.Source="🔀" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>-->
|
||||
</MenuItem>
|
||||
<MenuItem Header="{x:Static properties:Resources.Settings}" Command="{Binding Settings}">
|
||||
<MenuItem.Icon>
|
||||
<Image Width="16" Height="16" emoji:Image.Source="🛠️" />
|
||||
|
@ -71,6 +71,18 @@ namespace unison
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Shuffle
|
||||
{
|
||||
get
|
||||
{
|
||||
return new DelegateCommand
|
||||
{
|
||||
CommandAction = () => ((MainWindow)Application.Current.MainWindow).Shuffle_Clicked(null, null),
|
||||
CanExecuteFunc = () => true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand Settings
|
||||
{
|
||||
get
|
||||
|
@ -7,7 +7,7 @@
|
||||
<ApplicationIcon>Resources\icon-full.ico</ApplicationIcon>
|
||||
<Win32Resource></Win32Resource>
|
||||
<StartupObject>unison.App</StartupObject>
|
||||
<Version>1.1</Version>
|
||||
<Version>1.2</Version>
|
||||
<Company />
|
||||
<Authors>Théo Marchal</Authors>
|
||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
||||
|
Reference in New Issue
Block a user