diff --git a/App.xaml.cs b/App.xaml.cs index 53df18f..b657ee4 100644 --- a/App.xaml.cs +++ b/App.xaml.cs @@ -1,6 +1,6 @@ -using System.Globalization; -using System.Windows; +using System.Windows; using Hardcodet.Wpf.TaskbarNotification; +using unison.Handlers; namespace unison { @@ -11,12 +11,13 @@ namespace unison private SnapcastHandler _snapcast; private ShuffleHandler _shuffle; private MPDHandler _mpd; + private UpdateHandler _updater; protected override void OnStartup(StartupEventArgs e) { //debug language - //unison.Resources.Resources.Culture = CultureInfo.GetCultureInfo("fr-FR"); - //unison.Resources.Resources.Culture = CultureInfo.GetCultureInfo("es-ES"); + //unison.Resources.Resources.Culture = System.Globalization.CultureInfo.GetCultureInfo("fr-FR"); + //unison.Resources.Resources.Culture = System.Globalization.CultureInfo.GetCultureInfo("es-ES"); base.OnStartup(e); @@ -32,6 +33,9 @@ namespace unison _shuffle = new ShuffleHandler(); Current.Properties["shuffle"] = _shuffle; + + _updater = new UpdateHandler(); + Current.Properties["updater"] = _updater; Current.MainWindow = new MainWindow(); diff --git a/Handlers/MPDHandler.cs b/Handlers/MPDHandler.cs index 0078fd6..89eeaef 100644 --- a/Handlers/MPDHandler.cs +++ b/Handlers/MPDHandler.cs @@ -48,7 +48,7 @@ namespace unison private MpdStatus _currentStatus; private IMpdFile _currentSong; - private BitmapFrame _cover; + private BitmapImage _cover; public Statistics _stats; private readonly System.Timers.Timer _elapsedTimer; private DispatcherTimer _retryTimer; @@ -476,14 +476,12 @@ namespace unison else { using MemoryStream stream = new MemoryStream(data.ToArray()); - try - { - _cover = BitmapFrame.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); - } - catch - { - _cover = null; - } + _cover = new BitmapImage(); + _cover.BeginInit(); + _cover.CacheOption = BitmapCacheOption.OnLoad; + _cover.StreamSource = stream; + _cover.EndInit(); + _cover.Freeze(); } UpdateCover(); } @@ -525,7 +523,7 @@ namespace unison public IMpdFile GetCurrentSong() => _currentSong; public MpdStatus GetStatus() => _currentStatus; - public BitmapFrame GetCover() => _cover; + public BitmapImage GetCover() => _cover; public string GetVersion() => _version; public Statistics GetStats() => _stats; public double GetCurrentTime() => _currentTime; diff --git a/Handlers/RadioHandler.cs b/Handlers/RadioHandler.cs new file mode 100644 index 0000000..e371e51 --- /dev/null +++ b/Handlers/RadioHandler.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; +using RadioBrowser; +using RadioBrowser.Models; + +namespace unison.Handlers +{ + public class CountryListItem + { + public uint Count { get; set; } + public string Name { get; set; } + + public override string ToString() + { + if (Name == "") + return "None"; + return $"{Name} ({Count})"; + } + } + + public class StationListItem + { + public string Name { get; set; } + public string Codec { get; set; } + public string Tags { get; set; } + public int Bitrate { get; set; } + public Uri Url { get; set; } + + private string _country; + public string Country + { + get + { + if (_country.Length == 0) + return "🏴‍☠️"; + return string.Concat(_country.ToUpper().Select(x => char.ConvertFromUtf32(x + 0x1F1A5))); // return emoji + } + set + { + _country = value; + } + } + } + + internal class RadioHandler + { + private readonly RadioBrowserClient _radioBrowser; + private readonly bool _connected = true; + + public bool IsConnected() => _connected; + + + public RadioHandler() + { + try + { + _radioBrowser = new RadioBrowserClient(); + } + catch (Exception e) + { + Trace.WriteLine("Exception while connecting to RadioBrowser: " + e.Message); + return; + } + + _connected = true; + } + + public async Task> GetCountries() + { + return await _radioBrowser.Lists.GetCountriesAsync(); + } + + public async Task> AdvancedSearch(AdvancedSearchOptions options) + { + + return await _radioBrowser.Search.AdvancedAsync(options); + } + } +} diff --git a/Handlers/SnapcastHandler.cs b/Handlers/SnapcastHandler.cs index a4769e4..5d7d0f9 100644 --- a/Handlers/SnapcastHandler.cs +++ b/Handlers/SnapcastHandler.cs @@ -20,6 +20,16 @@ namespace unison } } + private void HandleExit(object sender, EventArgs e) + { + _snapcast.Kill(); + HasStarted = false; + Application.Current.Dispatcher.Invoke(() => + { + UpdateInterface(); + }); + } + public void UpdateInterface() { TaskbarIcon Systray = (TaskbarIcon)Application.Current.Properties["systray"]; @@ -42,16 +52,19 @@ namespace unison _snapcast.StartInfo.FileName = Properties.Settings.Default.snapcast_path + @"\snapclient.exe"; _snapcast.StartInfo.Arguments = $"--host {mpd._ipAddress}"; _snapcast.StartInfo.CreateNoWindow = !Properties.Settings.Default.snapcast_window; + _snapcast.EnableRaisingEvents = true; + _snapcast.Exited += new EventHandler(HandleExit); + try { _snapcast.Start(); } catch (Exception err) { - MessageBox.Show($"[{unison.Resources.Resources.Snapcast_Popup1}]\n" + - $"{unison.Resources.Resources.Snapcast_Popup2} {err.Message}\n\n" + - $"{unison.Resources.Resources.Snapcast_Popup3} {Properties.Settings.Default.snapcast_path}\n" + - $"{unison.Resources.Resources.Snapcast_Popup4}", + MessageBox.Show($"[{Resources.Resources.Snapcast_Popup1}]\n" + + $"{Resources.Resources.Snapcast_Popup2} {err.Message}\n\n" + + $"{Resources.Resources.Snapcast_Popup3} {Properties.Settings.Default.snapcast_path}\n" + + $"{Resources.Resources.Snapcast_Popup4}", "unison", MessageBoxButton.OK, MessageBoxImage.Error); return; } diff --git a/Handlers/UpdateHandler.cs b/Handlers/UpdateHandler.cs new file mode 100644 index 0000000..1af30e8 --- /dev/null +++ b/Handlers/UpdateHandler.cs @@ -0,0 +1,58 @@ +using System.Diagnostics; +using System.Windows; +using AutoUpdaterDotNET; + +namespace unison.Handlers +{ + internal class UpdateHandler + { + readonly string xmlFile = "https://raw.githubusercontent.com/ZetaKebab/unison/main/Installer/unison.xml"; + + private bool _UpdateAvailable = false; + public bool UpdateAvailable() => _UpdateAvailable; + + private bool _RequestedCheck = false; + + public UpdateHandler() + { + AutoUpdater.CheckForUpdateEvent += AutoUpdaterOnCheckForUpdateEvent; + Start(); + } + + public void Start(bool RequestCheck = false) + { + _RequestedCheck = RequestCheck; + AutoUpdater.Start(xmlFile); + } + + private string CutVersionNumber(string number) + { + return number.Substring(0, number.LastIndexOf(".")); + } + + private void AutoUpdaterOnCheckForUpdateEvent(UpdateInfoEventArgs args) + { + if (args.Error == null) + { + if (args.IsUpdateAvailable) + { + _UpdateAvailable = true; + string number = CutVersionNumber(args.CurrentVersion); + + MainWindow MainWin = (MainWindow)Application.Current.MainWindow; + MainWin.UpdateUpdateStatus(number); + + MessageBoxResult Result = MessageBox.Show($"{Resources.Resources.Update_Message1} {number}.\n{Resources.Resources.Update_Message2}", + "unison", MessageBoxButton.YesNo, MessageBoxImage.Information); + if (Result == MessageBoxResult.Yes) + AutoUpdater.DownloadUpdate(args); + } + else + { + if (_RequestedCheck) + MessageBox.Show($"{Resources.Resources.Update_NoUpdate}", "unison", MessageBoxButton.OK, MessageBoxImage.Information); + } + } + } + } +} diff --git a/Installer/unison.iss b/Installer/unison.iss new file mode 100644 index 0000000..88b793f --- /dev/null +++ b/Installer/unison.iss @@ -0,0 +1,43 @@ +#define Name "unison" +#define Version "1.3.1" +#define Snapcast "snapclient_0.26.0-1_win64" +#define Publisher "Tho Marchal" +#define URL "https://github.com/ZetaKebab/unison" +#define ExeName "unison.exe" + +[Setup] +AppName={#Name} +AppVersion={#Version} +AppVerName={#Name} v{#Version} +AppPublisher={#Publisher} +AppPublisherURL={#URL} +AppSupportURL={#URL} +AppUpdatesURL={#URL} +DefaultDirName={autopf}\{#Name} +DisableProgramGroupPage=yes +ArchitecturesInstallIn64BitMode=x64 +OutputBaseFilename="{#Name}-v{#Version}-setup" +OutputDir=..\publish\installer +SetupIconFile=..\Resources\icon-full.ico +UninstallDisplayIcon = "{app}\{#Name}.exe" +Compression=lzma +SolidCompression=yes +WizardStyle=modern + +[Languages] +Name: "english"; MessagesFile: "compiler:Default.isl" +Name: "french"; MessagesFile: "compiler:Languages\French.isl" +Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl" + +[Files] +Source: "..\publish\{#ExeName}"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\publish\LICENSE"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\publish\unison.exe"; DestDir: "{app}"; Flags: ignoreversion +Source: "..\publish\{#Snapcast}\*"; DestDir: "{app}\{#Snapcast}"; Flags: ignoreversion recursesubdirs createallsubdirs + +[Icons] +Name: "{group}\{#Name}"; Filename: "{app}\{#ExeName}" + +[Run] +Filename: "{app}\{#Name}.exe"; Parameters: "-frominstaller"; Flags: nowait postinstall skipifsilent + diff --git a/Installer/unison.xml b/Installer/unison.xml new file mode 100644 index 0000000..6d68f3d --- /dev/null +++ b/Installer/unison.xml @@ -0,0 +1,7 @@ + + + 1.3.1.0 + https://github.com/ZetaKebab/unison/releases/download/v1.3.1/unison-v1.3.1.zip + https://raw.githubusercontent.com/ZetaKebab/unison/main/CHANGELOG.md + false + \ No newline at end of file diff --git a/README.md b/README.md index 84d1c66..73646f2 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,8 @@ * lightweight window that can be toggled with shortcuts * music control through rebindable shortcuts -* shuffle panel -* [Snapcast](https://mjaggard.github.io/snapcast/) integration -* radio stations +* [Snapcast](https://github.com/badaix/snapcast) integration +* Radio stations ## Features diff --git a/Resources/Resources.Designer.cs b/Resources/Resources.Designer.cs index 16667a1..93607af 100644 --- a/Resources/Resources.Designer.cs +++ b/Resources/Resources.Designer.cs @@ -19,7 +19,7 @@ namespace unison.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class Resources { @@ -196,7 +196,7 @@ namespace unison.Resources { } /// - /// Looks up a localized string similar to Please note that since MPD passwords are not secure (they are sent in plain text to the server), there are saved as is in the setting file.. + /// Looks up a localized string similar to Please note that since MPD passwords are not secure (they are sent in plain text to the server), they are saved as is in the setting file.. /// public static string Settings_ConnectionPasswordInfo { get { @@ -617,5 +617,68 @@ namespace unison.Resources { return ResourceManager.GetString("StopSnapcast", resourceCulture); } } + + /// + /// Looks up a localized string similar to Check for updates. + /// + public static string Update_ButtonCheck { + get { + return ResourceManager.GetString("Update_ButtonCheck", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Start update. + /// + public static string Update_ButtonStart { + get { + return ResourceManager.GetString("Update_ButtonStart", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Update available! New version is. + /// + public static string Update_Message1 { + get { + return ResourceManager.GetString("Update_Message1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Install now?. + /// + public static string Update_Message2 { + get { + return ResourceManager.GetString("Update_Message2", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No update available.. + /// + public static string Update_NoUpdate { + get { + return ResourceManager.GetString("Update_NoUpdate", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to New version. + /// + public static string Update_String1 { + get { + return ResourceManager.GetString("Update_String1", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to available!. + /// + public static string Update_String2 { + get { + return ResourceManager.GetString("Update_String2", resourceCulture); + } + } } } diff --git a/Resources/Resources.es-ES.resx b/Resources/Resources.es-ES.resx index 8318afa..623747a 100644 --- a/Resources/Resources.es-ES.resx +++ b/Resources/Resources.es-ES.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Salir @@ -303,4 +303,25 @@ Parar Snapcast + + Buscar actualización + + + Actualizar + + + ¡Actualización disponible! La nueva versión es la + + + ¿Instalar ahora? + + + No actualización disponible. + + + ¡Nueva versión + + + disponible! + \ No newline at end of file diff --git a/Resources/Resources.fr-FR.resx b/Resources/Resources.fr-FR.resx index 8991b56..21da2bf 100644 --- a/Resources/Resources.fr-FR.resx +++ b/Resources/Resources.fr-FR.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Quitter @@ -298,9 +298,30 @@ Temps d'écoute écoulé : - MPD lancé depuis : + MPD lancé depuis : Stopper Snapcast + + Vérifier les mises à jour + + + Mettre à jour + + + Mise à jour disponible ! La nouvelle version est la + + + Installer maintenant ? + + + Pas de mise à jour disponible. + + + Nouvelle version + + + disponible ! + \ No newline at end of file diff --git a/Resources/Resources.resx b/Resources/Resources.resx index 50e7710..13bbaff 100644 --- a/Resources/Resources.resx +++ b/Resources/Resources.resx @@ -112,10 +112,10 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 Exit @@ -163,7 +163,7 @@ Connection - Please note that since MPD passwords are not secure (they are sent in plain text to the server), there are saved as is in the setting file. + Please note that since MPD passwords are not secure (they are sent in plain text to the server), they are saved as is in the setting file. Status: @@ -303,4 +303,25 @@ Stop Snapcast + + Check for updates + + + Start update + + + Update available! New version is + + + Install now? + + + No update available. + + + New version + + + available! + \ No newline at end of file diff --git a/Views/MainWindow.xaml.cs b/Views/MainWindow.xaml.cs index 80833e6..a8ebc37 100644 --- a/Views/MainWindow.xaml.cs +++ b/Views/MainWindow.xaml.cs @@ -9,6 +9,7 @@ using System.Windows.Controls.Primitives; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; +using unison.Handlers; namespace unison { @@ -302,6 +303,11 @@ namespace unison slider.ToolTip = (int)slider.Value; } + public void UpdateUpdateStatus(string version) + { + _settingsWin.UpdateUpdateStatus(version); + } + protected override void OnSourceInitialized(EventArgs e) { base.OnSourceInitialized(e); diff --git a/Views/Radios.xaml b/Views/Radios.xaml index 19a852a..df6eedb 100644 --- a/Views/Radios.xaml +++ b/Views/Radios.xaml @@ -37,7 +37,7 @@ -