Compare commits
	
		
			6 Commits
		
	
	
		
			v1.2
			...
			6ad4d9c813
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 6ad4d9c813 | |||
| c93a9a326e | |||
| c055c59de7 | |||
| 4c71d6a6e0 | |||
| 3685c369b4 | |||
| e0d640532c | 
| @@ -515,21 +515,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) | ||||
| @@ -234,6 +267,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(); | ||||
|   | ||||
| @@ -54,60 +54,6 @@ | ||||
|                     </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="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="{x:Static properties:Resources.Settings_Shortcuts}"> | ||||
|                     <DockPanel Margin="8"> | ||||
|                         <GroupBox DockPanel.Dock="Top" Padding="0,4,0,0"> | ||||
| @@ -209,13 +155,97 @@ | ||||
|                                     </StackPanel> | ||||
|  | ||||
|                                     <Button Content="{x:Static properties:Resources.Settings_SnapcastResetButton}" Margin="0,10,0,0" Width="120" Click="ShortcutsReset_Clicked"/> | ||||
|  | ||||
|                                 </StackPanel> | ||||
|                             </Grid> | ||||
|                         </GroupBox> | ||||
|                     </DockPanel> | ||||
|                 </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> | ||||
|                                     <StackPanel Orientation="Horizontal"> | ||||
|                                         <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> | ||||
|                                     <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/> | ||||
|                                          | ||||
|                                         <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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user