10 Commits

Author SHA1 Message Date
309f42bad1 Update RadioBrowser link 2025-06-09 00:47:45 +02:00
8b0d2153b0 Save all window positions 2025-06-08 02:09:48 +02:00
2082072532 Windows 11 design compatibility 2025-06-08 01:29:22 +02:00
f7df25372d Fix regression in Systray text display 2025-06-07 01:51:39 +02:00
ff9f92424e Better way of handling minimization of windows 2025-06-07 00:45:05 +02:00
0c0809c111 Add security to QueryStats response to avoid crashes 2025-06-06 19:01:34 +02:00
b32e75f15d Hide windows when clicking corresponding buttons if they were visible 2025-06-06 01:30:14 +02:00
46b96c0c5d Shuffle: Add clear queue and play queue button 2025-06-06 00:46:53 +02:00
0a04e3c6ce Bump components
.NET 6.0 => 8.0
Snapcast 0.27 => 0.31
Autoupdater.NET.Official 1.8.0 => 1.9.2
Hardcodet.NotifyIcon.Wpf 1.1.0 => 2.0.1
MpcNET 1.4.0 => 1.6.6
2025-06-01 15:34:25 +02:00
b5cb6e4c3a Update Snapcast, AutoUpdater and RadioBrowser 2023-04-30 18:28:54 +02:00
33 changed files with 309 additions and 79 deletions

View File

@ -23,7 +23,7 @@
<value>False</value>
</setting>
<setting name="snapcast_path" serializeAs="String">
<value>snapclient_0.26.0-1_win64</value>
<value>snapcast_0.31</value>
</setting>
<setting name="snapcast_port" serializeAs="String">
<value>1704</value>

View File

@ -677,15 +677,24 @@ namespace unison
if (Response == null)
return;
_stats.Songs = int.Parse(Response["songs"]);
_stats.Albums = int.Parse(Response["albums"]);
_stats.Artists = int.Parse(Response["artists"]);
_stats.Uptime = FormatTime(TimeSpan.FromSeconds(int.Parse(Response["uptime"])));
_stats.TotalPlaytime = FormatTime(TimeSpan.FromSeconds(int.Parse(Response["db_playtime"])));
_stats.TotalTimePlayed = FormatTime(TimeSpan.FromSeconds(int.Parse(Response["playtime"])));
if (Response.ContainsKey("songs"))
_stats.Songs = int.Parse(Response["songs"]);
if (Response.ContainsKey("albums"))
_stats.Albums = int.Parse(Response["albums"]);
if (Response.ContainsKey("artists"))
_stats.Artists = int.Parse(Response["artists"]);
if (Response.ContainsKey("uptime"))
_stats.Uptime = FormatTime(TimeSpan.FromSeconds(int.Parse(Response["uptime"])));
if (Response.ContainsKey("db_playtime"))
_stats.TotalPlaytime = FormatTime(TimeSpan.FromSeconds(int.Parse(Response["db_playtime"])));
if (Response.ContainsKey("playtime"))
_stats.TotalTimePlayed = FormatTime(TimeSpan.FromSeconds(int.Parse(Response["playtime"])));
DateTime date = new DateTime(1970, 1, 1);
if (Response.ContainsKey("db_update"))
date = date.AddSeconds(int.Parse(Response["db_update"])).ToLocalTime();
DateTime date = new DateTime(1970, 1, 1).AddSeconds(int.Parse(Response["db_update"])).ToLocalTime();
string dayOfWeek = Resources.Resources.Culture.DateTimeFormat.GetDayName(date.DayOfWeek);
_stats.DatabaseUpdate = dayOfWeek + " " + date.ToString("dd/MM/yyyy @ HH:mm");
}

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
@ -34,8 +35,9 @@ namespace unison
SongList.Clear();
int song = _mpd.GetStats().Songs;
IEnumerable<IMpdFile> response = await _mpd.SafelySendCommandAsync(new SearchCommand(filter, 0, song + 1));
int songTotal = _mpd.GetStats().Songs;
IEnumerable<IMpdFile> response = await _mpd.SafelySendCommandAsync(new SearchCommand(filter, 0, songTotal + 1));
foreach (IMpdFile file in response)
SongList.Add(file.Path);
}
@ -45,7 +47,7 @@ namespace unison
if (token.IsCancellationRequested)
return;
int AddedSongs = 0;
int addedSongs = 0;
var commandList = new CommandList();
int songTotal = _mpd.GetStats().Songs;
@ -54,13 +56,13 @@ namespace unison
{
int song = new Random().Next(0, songTotal - 1);
commandList.Add(new SearchAddCommand(new FilterTag(MpdTags.Title, "", FilterOperator.Contains), song, song + 1));
AddedSongs++;
// play if stopped or unknown state (no queue managing at the moment, so mandatory)
if (i == 0 && (_mpd.GetStatus().State != MpdState.Play && _mpd.GetStatus().State != MpdState.Pause))
commandList.Add(new PlayCommand(0));
addedSongs++;
}
// play if stopped or unknown state (no queue managing at the moment, so mandatory)
if ((_mpd.GetStatus().State != MpdState.Play && _mpd.GetStatus().State != MpdState.Pause))
commandList.Add(new PlayCommand(0));
await _mpd.SafelySendCommandAsync(commandList);
}

View File

@ -1,6 +1,6 @@
#define Name "unison"
#define Version "1.4"
#define Snapcast "snapclient_0.26.0-1_win64"
#define Snapcast "snapcast_0.31"
#define Publisher "Th<54>o Marchal"
#define URL "https://github.com/ZetaKebab/unison"
#define ExeName "unison.exe"

View File

@ -1,4 +1,4 @@
MIT License Copyright (c) 2022 Théo Marchal
MIT License Copyright (c) 2025 Théo Marchal
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

View File

@ -12,7 +12,7 @@ namespace unison.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.4.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.13.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@ -85,7 +85,7 @@ namespace unison.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("snapclient_0.26.0-1_win64")]
[global::System.Configuration.DefaultSettingValueAttribute("snapcast_0.31")]
public string snapcast_path {
get {
return ((string)(this["snapcast_path"]));
@ -289,7 +289,7 @@ namespace unison.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("100")]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public double MainWindowTop {
get {
return ((double)(this["MainWindowTop"]));
@ -301,7 +301,7 @@ namespace unison.Properties {
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("100")]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public double MainWindowLeft {
get {
return ((double)(this["MainWindowLeft"]));
@ -310,5 +310,77 @@ namespace unison.Properties {
this["MainWindowLeft"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public double RadiosWindowTop {
get {
return ((double)(this["RadiosWindowTop"]));
}
set {
this["RadiosWindowTop"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("1000")]
public double RadiosWindowLeft {
get {
return ((double)(this["RadiosWindowLeft"]));
}
set {
this["RadiosWindowLeft"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("10")]
public double ShuffleWindowTop {
get {
return ((double)(this["ShuffleWindowTop"]));
}
set {
this["ShuffleWindowTop"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("330")]
public double ShuffleWindowLeft {
get {
return ((double)(this["ShuffleWindowLeft"]));
}
set {
this["ShuffleWindowLeft"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("330")]
public double SettingsWindowTop {
get {
return ((double)(this["SettingsWindowTop"]));
}
set {
this["SettingsWindowTop"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("600")]
public double SettingsWindowLeft {
get {
return ((double)(this["SettingsWindowLeft"]));
}
set {
this["SettingsWindowLeft"] = value;
}
}
}
}

View File

@ -18,7 +18,7 @@
<Value Profile="(Default)">False</Value>
</Setting>
<Setting Name="snapcast_path" Type="System.String" Scope="User">
<Value Profile="(Default)">snapclient_0.26.0-1_win64</Value>
<Value Profile="(Default)">snapcast_0.31</Value>
</Setting>
<Setting Name="snapcast_port" Type="System.Int32" Scope="User">
<Value Profile="(Default)">1704</Value>
@ -69,10 +69,28 @@
<Value Profile="(Default)">13</Value>
</Setting>
<Setting Name="MainWindowTop" Type="System.Double" Scope="User">
<Value Profile="(Default)">100</Value>
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="MainWindowLeft" Type="System.Double" Scope="User">
<Value Profile="(Default)">100</Value>
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="RadiosWindowTop" Type="System.Double" Scope="User">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="RadiosWindowLeft" Type="System.Double" Scope="User">
<Value Profile="(Default)">1000</Value>
</Setting>
<Setting Name="ShuffleWindowTop" Type="System.Double" Scope="User">
<Value Profile="(Default)">10</Value>
</Setting>
<Setting Name="ShuffleWindowLeft" Type="System.Double" Scope="User">
<Value Profile="(Default)">330</Value>
</Setting>
<Setting Name="SettingsWindowTop" Type="System.Double" Scope="User">
<Value Profile="(Default)">330</Value>
</Setting>
<Setting Name="SettingsWindowLeft" Type="System.Double" Scope="User">
<Value Profile="(Default)">600</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -60,6 +60,15 @@ namespace unison.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Clear queue.
/// </summary>
public static string Clear_Queue {
get {
return ResourceManager.GetString("Clear_Queue", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Database.
/// </summary>
@ -213,6 +222,24 @@ namespace unison.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Play queue.
/// </summary>
public static string Play_Queue {
get {
return ResourceManager.GetString("Play_Queue", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Queue management.
/// </summary>
public static string Queue_Management {
get {
return ResourceManager.GetString("Queue_Management", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Country.
/// </summary>

View File

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Clear_Queue" xml:space="preserve">
<value>Borrar cola</value>
</data>
<data name="Database" xml:space="preserve">
<value>Base de datos</value>
</data>
@ -168,6 +171,12 @@
<data name="Operator_IsNot" xml:space="preserve">
<value>no es</value>
</data>
<data name="Play_Queue" xml:space="preserve">
<value>Reproducir cola</value>
</data>
<data name="Queue_Management" xml:space="preserve">
<value>Gestión de cola</value>
</data>
<data name="Radios" xml:space="preserve">
<value>Radios</value>
</data>

View File

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Clear_Queue" xml:space="preserve">
<value>Effacer la file</value>
</data>
<data name="Database" xml:space="preserve">
<value>Base de donnée</value>
</data>
@ -168,6 +171,12 @@
<data name="Operator_IsNot" xml:space="preserve">
<value>n'est pas</value>
</data>
<data name="Play_Queue" xml:space="preserve">
<value>Jouer la file</value>
</data>
<data name="Queue_Management" xml:space="preserve">
<value>Gestion de file</value>
</data>
<data name="Radios" xml:space="preserve">
<value>Radios</value>
</data>

View File

@ -117,6 +117,9 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Clear_Queue" xml:space="preserve">
<value>Clear queue</value>
</data>
<data name="Database" xml:space="preserve">
<value>Database</value>
</data>
@ -168,6 +171,12 @@
<data name="Operator_IsNot" xml:space="preserve">
<value>is not</value>
</data>
<data name="Play_Queue" xml:space="preserve">
<value>Play queue</value>
</data>
<data name="Queue_Management" xml:space="preserve">
<value>Queue management</value>
</data>
<data name="Radios" xml:space="preserve">
<value>Radios</value>
</data>

View File

@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib" xmlns:sys="clr-namespace:System;assembly=System.Runtime">
<system:String x:Key="snapcastPath">snapclient_0.26.0-1_win64</system:String>
<system:String x:Key="snapcastPath">snapcast_0.31</system:String>
<system:String x:Key="snapcastPort">1704</system:String>
<system:String x:Key="playButton">&#xedb4;</system:String>

View File

@ -17,7 +17,7 @@
</Style>
</Window.Resources>
<Grid Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" MinHeight="270" MinWidth="700">
<Grid Background="{DynamicResource {x:Static SystemColors.ControlLightLightBrushKey}}" MinHeight="270" MinWidth="700" Margin="0,10,0,0">
<Grid x:Name="TopLayout" Margin="10,0,10,0" VerticalAlignment="Stretch" Width="Auto" Height="Auto">
<Grid x:Name="Display" HorizontalAlignment="Stretch" VerticalAlignment="Top" Margin="225,0,0,0" Height="Auto" Width="Auto">
<GroupBox Height="220" VerticalAlignment="Center">
@ -114,14 +114,14 @@
<StackPanel HorizontalAlignment="Left" Orientation="Horizontal" VerticalAlignment="Center" Margin="10,0,0,0">
<Button x:Name="Shuffle" Padding="5, 2" Click="Shuffle_Clicked" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}" Margin="0,0,10,0">
<StackPanel Orientation="Horizontal">
<emoji:TextBlock Text="🔁" Padding="0,0,0,2"/>
<TextBlock Text="🔁" Margin="0,0,0,2"/>
<TextBlock Text="{x:Static properties:Resources.Shuffle}" Margin="5, 0, 0, 0"/>
</StackPanel>
</Button>
<Button x:Name="Radio" Padding="5, 2" HorizontalAlignment="Left" Click="Radios_Clicked" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}" IsEnabled="False">
<StackPanel Orientation="Horizontal">
<emoji:TextBlock Text="📻" Padding="0,0,0,2"/>
<TextBlock Text="📻" Padding="0,0,0,2"/>
<TextBlock Text="{x:Static properties:Resources.Radios}" Margin="5, 0, 0, 0"/>
</StackPanel>
</Button>
@ -139,14 +139,14 @@
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,10,0">
<Button x:Name="Snapcast" HorizontalAlignment="Left" VerticalAlignment="Center" Click="Snapcast_Clicked" Margin="0,0,10,0" Padding="5, 2" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" FocusVisualStyle="{x:Null}" IsEnabled="False">
<StackPanel Orientation="Horizontal">
<emoji:TextBlock Text="🔊" Padding="0,0,0,2"/>
<TextBlock Text="🔊" Padding="0,0,0,2"/>
<TextBlock x:Name="SnapcastText" Text="{x:Static properties:Resources.StartSnapcast}" Margin="5, 0, 0, 0"/>
</StackPanel>
</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"/>
<TextBlock Text="🛠️" Padding="0,0,0,2"/>
<TextBlock Text="{x:Static properties:Resources.Settings}" Margin="5, 0, 0, 0"/>
</StackPanel>
</Button>

View File

@ -17,17 +17,22 @@ namespace unison
private readonly Settings _settingsWin;
private readonly Radios _radiosWin;
private readonly Shuffle _shuffleWin;
private readonly DispatcherTimer _timer;
private readonly MPDHandler _mpd;
public Settings GetSettings() => _settingsWin;
public Radios GetRadios() => _radiosWin;
public Shuffle GetShuffle() => _shuffleWin;
private readonly DispatcherTimer _timer;
private readonly MPDHandler _mpd;
public MainWindow()
{
InitHwnd();
InitializeComponent();
DefaultState(true);
WindowState = WindowState.Minimized;
Top = Properties.Settings.Default.MainWindowTop;
Left = Properties.Settings.Default.MainWindowLeft;
@ -259,29 +264,47 @@ namespace unison
public void Radios_Clicked(object sender, RoutedEventArgs e)
{
_radiosWin.Show();
_radiosWin.Activate();
if (_radiosWin.WindowState == WindowState.Minimized)
{
_radiosWin.Show();
_radiosWin.Activate();
_radiosWin.WindowState = WindowState.Normal;
}
else if (_radiosWin.WindowState == WindowState.Normal)
{
_radiosWin.Hide();
_radiosWin.WindowState = WindowState.Minimized;
}
}
public void Shuffle_Clicked(object sender, RoutedEventArgs e)
{
_shuffleWin.Show();
_shuffleWin.Activate();
if (_shuffleWin.WindowState == WindowState.Minimized)
{
_shuffleWin.Show();
_shuffleWin.Activate();
_shuffleWin.WindowState = WindowState.Normal;
}
else if (_shuffleWin.WindowState == WindowState.Normal)
{
_shuffleWin.Hide();
_shuffleWin.WindowState = WindowState.Minimized;
}
}
public void Settings_Clicked(object sender, RoutedEventArgs e)
{
_settingsWin.Show();
_settingsWin.Activate();
if (_settingsWin.WindowState == WindowState.Minimized)
{
_settingsWin.Show();
_settingsWin.Activate();
_settingsWin.WindowState = WindowState.Normal;
}
else if (_settingsWin.WindowState == WindowState.Normal)
{
_settingsWin.Hide();
_settingsWin.WindowState = WindowState.Minimized;
}
}
private void TimeSlider_DragStarted(object sender, DragStartedEventArgs e)

View File

@ -6,15 +6,15 @@
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
xmlns:properties="clr-namespace:unison.Resources"
mc:Ignorable="d"
Title="Radios" Closing="Window_Closing" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
Title="Radios" Closing="Window_Closing" LocationChanged="Window_LocationChanged" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
<Grid>
<Grid Margin="0,5,0,0">
<StackPanel>
<StackPanel HorizontalAlignment="Left" Orientation="Vertical" Margin="5,0,5,0">
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="📻"/>
<Run Text="📻"/>
<Run Text="{x:Static properties:Resources.Radio_SearchStation}"/>
</TextBlock>
</GroupBox.Header>

View File

@ -23,6 +23,12 @@ namespace unison
{
InitializeComponent();
Initialize();
InitHwnd();
WindowState = WindowState.Minimized;
Top = Properties.Settings.Default.RadiosWindowTop;
Left = Properties.Settings.Default.RadiosWindowLeft;
}
public async void Initialize()
@ -169,5 +175,12 @@ namespace unison
WindowInteropHelper helper = new(this);
helper.EnsureHandle();
}
private void Window_LocationChanged(object sender, EventArgs e)
{
Properties.Settings.Default.RadiosWindowTop = Top;
Properties.Settings.Default.RadiosWindowLeft = Left;
Properties.Settings.Default.Save();
}
}
}

View File

@ -6,7 +6,7 @@
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
xmlns:properties="clr-namespace:unison.Resources" xmlns:sys="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Closing="Window_Closing" Title="{x:Static properties:Resources.Settings}" ResizeMode="CanMinimize" Icon="/Resources/icon-full.ico" WindowStyle="ToolWindow" SizeToContent="WidthAndHeight">
Title="{x:Static properties:Resources.Settings}" Closing="Window_Closing" LocationChanged="Window_LocationChanged" ResizeMode="CanMinimize" Icon="/Resources/icon-full.ico" WindowStyle="ToolWindow" SizeToContent="WidthAndHeight">
<Window.Resources>
<x:Array x:Key="ShortcutItems" Type="sys:String">
@ -25,7 +25,7 @@
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="📶"/>
<Run Text="📶"/>
<Run Text="{x:Static properties:Resources.Settings_Connection}"/>
</TextBlock>
</GroupBox.Header>
@ -64,7 +64,7 @@
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="⌨️ "/>
<Run Text="⌨️"/>
<Run Text="{x:Static properties:Resources.Settings_Shortcuts}"></Run>
</TextBlock>
</GroupBox.Header>
@ -170,7 +170,7 @@
<DockPanel Margin="8">
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<emoji:TextBlock Text="🔊 Snapcast"/>
<Run Text="🔊 Snapcast"/>
</GroupBox.Header>
<Grid VerticalAlignment="Top">
<StackPanel>
@ -201,8 +201,8 @@
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="🔁 "/>
<Run Text="{x:Static properties:Resources.Shuffle}"></Run>
<Run Text="🔁"/>
<Run Text="{x:Static properties:Resources.Shuffle}"/>
</TextBlock>
</GroupBox.Header>
<Grid MaxWidth="500">
@ -230,7 +230,7 @@
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="📊"/>
<Run Text="📊"/>
<Run Text="{x:Static properties:Resources.Database}"/>
</TextBlock>
</GroupBox.Header>
@ -262,7 +262,7 @@
<DockPanel Margin="8">
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0">
<GroupBox.Header>
<emoji:TextBlock Text="🎶 unison"/>
<Run Text="🎶 unison"/>
</GroupBox.Header>
<Grid VerticalAlignment="Top">
<StackPanel Orientation="Vertical">
@ -281,7 +281,7 @@
※ <Hyperlink NavigateUri="https://github.com/Difegue/MpcNET" RequestNavigate="Hyperlink_RequestNavigate">MpcNET</Hyperlink><LineBreak/>
※ <Hyperlink NavigateUri="https://github.com/hardcodet/wpf-notifyicon" RequestNavigate="Hyperlink_RequestNavigate">wpf-notifyicon</Hyperlink><LineBreak/>
※ <Hyperlink NavigateUri="https://github.com/samhocevar/emoji.wpf" RequestNavigate="Hyperlink_RequestNavigate">Emoji.WPF</Hyperlink><LineBreak/>
※ <Hyperlink NavigateUri="https://github.com/tof4/RadioBrowser" RequestNavigate="Hyperlink_RequestNavigate">RadioBrowser</Hyperlink><LineBreak/>
※ <Hyperlink NavigateUri="https://git.sr.ht/~youkai/RadioBrowser.NET" RequestNavigate="Hyperlink_RequestNavigate">RadioBrowser</Hyperlink><LineBreak/>
※ <Hyperlink NavigateUri="https://github.com/ravibpatel/AutoUpdater.NET" RequestNavigate="Hyperlink_RequestNavigate">AutoUpdater.NET</Hyperlink><LineBreak/>
※ <Hyperlink NavigateUri="https://github.com/badaix/snapcast" RequestNavigate="Hyperlink_RequestNavigate">Snapcast</Hyperlink>
</TextBlock>
@ -308,7 +308,7 @@
<GroupBox DockPanel.Dock="Top" Padding="0,4,0,0" Margin="0,10,0,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="📝 "/>
<Run Text="📝"/>
<Run Text="{x:Static properties:Resources.Settings_License}" />
</TextBlock>
</GroupBox.Header>

View File

@ -45,11 +45,13 @@ namespace unison
{
InitHwnd();
InitializeComponent();
Initialize();
DataContext = this;
WindowState = WindowState.Minimized;
Initialize();
Top = Properties.Settings.Default.SettingsWindowTop;
Left = Properties.Settings.Default.SettingsWindowLeft;
}
void Initialize()
@ -207,6 +209,13 @@ namespace unison
helper.EnsureHandle();
}
private void Window_LocationChanged(object sender, EventArgs e)
{
Properties.Settings.Default.SettingsWindowTop = Top;
Properties.Settings.Default.SettingsWindowLeft = Left;
Properties.Settings.Default.Save();
}
public void SaveSettings()
{
Properties.Settings.Default.mpd_host = MpdHost.Text;

View File

@ -6,7 +6,7 @@
xmlns:emoji="clr-namespace:Emoji.Wpf;assembly=Emoji.Wpf"
xmlns:properties="clr-namespace:unison.Resources" xmlns:sys="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
Title="Shuffle" Closing="Window_Closing" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
Title="Shuffle" Closing="Window_Closing" LocationChanged="Window_LocationChanged" SizeToContent="WidthAndHeight" ResizeMode="NoResize">
<Window.Resources>
<x:Array x:Key="FilterType" Type="sys:String">
@ -42,13 +42,13 @@
</DataTemplate>
</Window.Resources>
<Grid>
<Grid Margin="0,5,0,0">
<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="🔡"/>
<Run Text="{x:Static properties:Resources.Shuffle_Filter}"/>
</TextBlock>
</GroupBox.Header>
@ -80,8 +80,8 @@
<GroupBox DockPanel.Dock="Right" Padding="0,4,0,0" Width="300">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text=""/>
<Run Text="{x:Static properties:Resources.Shuffle_Queue}"/>
<Run Text="🧾"/>
<Run Text="{x:Static properties:Resources.Queue_Management}"/>
</TextBlock>
</GroupBox.Header>
<StackPanel Orientation="Vertical" Margin="5,5,5,0">
@ -96,13 +96,18 @@
</TextBlock>
<TextBlock x:Name="SearchStatus2" Text="{x:Static properties:Resources.Shuffle_ButtonMessage3}" Margin="3,3,0,0" FontStyle="Italic" Visibility="Collapsed"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,15,0,0">
<Button Content="{x:Static properties:Resources.Clear_Queue}" Click="ClearQueue_Clicked" Padding="5, 2" HorizontalAlignment="Left" FocusVisualStyle="{x:Null}"/>
<Button Content="{x:Static properties:Resources.Play_Queue}" Click="StartQueue_Clicked" Padding="5, 2" Margin="5, 0" HorizontalAlignment="Left" FocusVisualStyle="{x:Null}"/>
</StackPanel>
</StackPanel>
</GroupBox>
<GroupBox DockPanel.Dock="Left" Padding="0,4,0,0" Width="260" Margin="0,0,5,0">
<GroupBox.Header>
<TextBlock>
<emoji:EmojiInline Text="♾️"/>
<Run Text="♾️"/>
<Run Text="{x:Static properties:Resources.Shuffle_Continuous}"/>
</TextBlock>
</GroupBox.Header>

View File

@ -32,11 +32,18 @@ namespace unison
public Shuffle()
{
InitializeComponent();
InitHwnd();
GenreList = new();
FolderList = new();
Filters = new();
SongFilterNumber.Text = "0";
WindowState = WindowState.Minimized;
Top = Properties.Settings.Default.ShuffleWindowTop;
Left = Properties.Settings.Default.ShuffleWindowLeft;
_mpd = (MPDHandler)Application.Current.Properties["mpd"];
_shuffle = (ShuffleHandler)Application.Current.Properties["shuffle"];
}
@ -55,7 +62,7 @@ namespace unison
if (token.IsCancellationRequested)
return;
List<string> Response = await _mpd.SafelySendCommandAsync(new ListCommand(MpdTags.Genre, null, null));
List<string> Response = await _mpd.SafelySendCommandAsync(new ListCommand(MpdTags.Genre, null, null, null));
if (Response == null)
return;
@ -375,6 +382,16 @@ namespace unison
AddToQueue();
}
public void ClearQueue_Clicked(object sender, RoutedEventArgs e)
{
_mpd.ClearQueue();
}
public void StartQueue_Clicked(object sender, RoutedEventArgs e)
{
_mpd.PlayCommand();
}
public bool GetContinuous()
{
return _continuous;
@ -418,5 +435,12 @@ namespace unison
WindowInteropHelper helper = new(this);
helper.EnsureHandle();
}
private void Window_LocationChanged(object sender, EventArgs e)
{
Properties.Settings.Default.ShuffleWindowTop = Top;
Properties.Settings.Default.ShuffleWindowLeft = Left;
Properties.Settings.Default.Save();
}
}
}

View File

@ -3,6 +3,7 @@ using System.Windows.Input;
using System.Reflection;
using System.ComponentModel;
using System;
using System.Diagnostics;
namespace unison
{
@ -32,7 +33,7 @@ namespace unison
CanExecuteFunc = () => true
};
public static string SnapcastText
public string SnapcastText
{
get
{
@ -49,7 +50,7 @@ namespace unison
{
CommandAction = () =>
{
Application.Current.Dispatcher.BeginInvoke(new Action(() => OnPropertyChanged("SnapcastText")));
Application.Current.Dispatcher.BeginInvoke(new Action(() => OnPropertyChanged(SnapcastText)));
SnapcastHandler snapcast = (SnapcastHandler)Application.Current.Properties["snapcast"];
snapcast.LaunchOrExit();

BIN
snapcast_0.31/FLAC.dll Normal file

Binary file not shown.

BIN
snapcast_0.31/opus.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,12 +2,12 @@
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
<ApplicationIcon>Resources\icon-full.ico</ApplicationIcon>
<Win32Resource></Win32Resource>
<StartupObject>unison.App</StartupObject>
<Version>1.4</Version>
<Version>1.4-dev</Version>
<Company />
<Authors>Théo Marchal</Authors>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
@ -52,11 +52,11 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Autoupdater.NET.Official" Version="1.7.6" />
<PackageReference Include="Autoupdater.NET.Official" Version="1.9.2" />
<PackageReference Include="Emoji.Wpf" Version="0.3.4" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="1.1.0" />
<PackageReference Include="RadioBrowser" Version="0.6.1" />
<PackageReference Include="MpcNET" Version="1.4.0" />
<PackageReference Include="Hardcodet.NotifyIcon.Wpf" Version="2.0.1" />
<PackageReference Include="RadioBrowser" Version="0.7.0" />
<PackageReference Include="MpcNET" Version="1.6.6" />
</ItemGroup>
<ItemGroup>
@ -90,25 +90,25 @@
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<None Update="snapclient_0.26.0-1_win64\FLAC.dll">
<None Update="snapcast_0.31\FLAC.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="snapclient_0.26.0-1_win64\ogg.dll">
<None Update="snapcast_0.31\ogg.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="snapclient_0.26.0-1_win64\opus.dll">
<None Update="snapcast_0.31\opus.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="snapclient_0.26.0-1_win64\README.txt">
<None Update="snapcast_0.31\README.txt">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="snapclient_0.26.0-1_win64\snapclient.exe">
<None Update="snapcast_0.31\snapclient.exe">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="snapclient_0.26.0-1_win64\soxr.dll">
<None Update="snapcast_0.31\soxr.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="snapclient_0.26.0-1_win64\vorbis.dll">
<None Update="snapcast_0.31\vorbis.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>