diff --git a/BreadPlayer.Core/Engines/BASSEngine/BASSPlayerEngine.cs b/BreadPlayer.Core/Engines/BASSEngine/BASSPlayerEngine.cs index 0ed605c..6210145 100644 --- a/BreadPlayer.Core/Engines/BASSEngine/BASSPlayerEngine.cs +++ b/BreadPlayer.Core/Engines/BASSEngine/BASSPlayerEngine.cs @@ -105,40 +105,51 @@ public async void Dispose() public async Task ChangeDevice(string deviceName = null) { if (deviceName != null) - await InitializeSwitch.NotificationManager.ShowMessageAsync($"Transitioning to {deviceName}.", 5); + await InitializeSwitch.NotificationManager.ShowStatusBarMessageAsync($"Transitioning to {deviceName}."); - await Task.Run(() => + await Task.Run(async () => { - var count = Bass.DeviceCount; - for (var i = 0; i < count; i++) + try { - var deviceInfo = Bass.GetDeviceInfo(i); - if (deviceInfo.IsDefault && deviceInfo.IsEnabled) + var count = Bass.DeviceCount; + for (var i = 0; i < count; i++) { - var isPlaying = PlayerState == PlayerState.Playing; - if (isPlaying) + var deviceInfo = Bass.GetDeviceInfo(i); + if (deviceInfo.IsDefault && deviceInfo.IsEnabled) { - Bass.ChannelPause(_handle); - PlayerState = PlayerState.Paused; - } + var isPlaying = PlayerState == PlayerState.Playing; + if (isPlaying) + { + Bass.ChannelPause(_handle); + PlayerState = PlayerState.Paused; + } - if (InitializeSwitch.IsMobile) - NativeMethods.BASS_SetConfig(NativeMethods.BassConfigDevBuffer, (int)DeviceBufferSize); + if (InitializeSwitch.IsMobile) + NativeMethods.BASS_SetConfig(NativeMethods.BassConfigDevBuffer, (int)DeviceBufferSize); - Bass.Init(); - Bass.ChannelSetDevice(_handle, i); - if (isPlaying) - { - Bass.ChannelPlay(_handle); - PlayerState = PlayerState.Playing; + Bass.Init(); + Bass.ChannelSetDevice(_handle, i); + if (isPlaying) + { + Bass.ChannelPlay(_handle); + PlayerState = PlayerState.Playing; + } + return; } - return; } } + catch(Exception ex) + { + BLogger.E($"Transition failed.", ex); + await InitializeSwitch.NotificationManager.ShowStatusBarMessageAsync($"Failed to transtion. Reason: {Bass.LastError}"); + } + finally + { + if (deviceName != null) + await InitializeSwitch.NotificationManager.ShowStatusBarMessageAsync($"Transition to {deviceName} complete."); + } }); - if (deviceName != null) - await InitializeSwitch.NotificationManager.ShowMessageAsync($"Transition to {deviceName} complete.", 5); } public async Task LoadURLAsync(Mediafile mediafile, string uri) { diff --git a/BreadPlayer.Core/Engines/BASSEngine/BassEqualizer.cs b/BreadPlayer.Core/Engines/BASSEngine/BassEqualizer.cs index 6c48e51..eed8c5d 100644 --- a/BreadPlayer.Core/Engines/BASSEngine/BassEqualizer.cs +++ b/BreadPlayer.Core/Engines/BASSEngine/BassEqualizer.cs @@ -5,6 +5,7 @@ using ManagedBass; using ManagedBass.Fx; using System; +using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; @@ -23,7 +24,7 @@ public BassEqualizer(int coreHandle) IsPreampAvailable = true; Bands = new ObservableCollection(); - Presets = new ObservableCollection(new ConfigSaver().GetSettings()); + Presets = new ObservableCollection((IEnumerable)new ConfigSaver().GetSettings()); EqualizerSettings = InitializeSwitch.EqualizerSettingsHelper.LoadEqualizerSettings("CustomEq").settings; Name = EqualizerSettings.Name; SelectedPreset = Presets.IndexOf(Presets.FirstOrDefault(t => t.Name == EqualizerSettings.Name)); diff --git a/BreadPlayer.Core/Engines/Interfaces/IEqualizer.cs b/BreadPlayer.Core/Engines/Interfaces/IEqualizer.cs index a0ccf67..215cea8 100644 --- a/BreadPlayer.Core/Engines/Interfaces/IEqualizer.cs +++ b/BreadPlayer.Core/Engines/Interfaces/IEqualizer.cs @@ -23,7 +23,7 @@ public abstract class Equalizer : ObservableObject new[] {16000f, 1f, 0f } }; public IEqualizerSettings EqualizerSettings { get; set; } - public ObservableCollection Presets { get; set; } + public ObservableCollection Presets { get; set; } private int _selectedPreset = -1; public int SelectedPreset diff --git a/BreadPlayer.Interfaces/INotificationManager.cs b/BreadPlayer.Interfaces/INotificationManager.cs index f0db9fe..0f2197e 100644 --- a/BreadPlayer.Interfaces/INotificationManager.cs +++ b/BreadPlayer.Interfaces/INotificationManager.cs @@ -8,7 +8,7 @@ public interface INotificationManager Task ShowMessageBoxAsync(string message, string title); Task ShowMessageAsync(string message, int duration = 10); - + Task ShowStatusBarMessageAsync(string message); void SendUpcomingSongNotification(IMediafile mediaFile); } } \ No newline at end of file diff --git a/BreadPlayer.Views.UWP/Common/NotificationManager.cs b/BreadPlayer.Views.UWP/Common/NotificationManager.cs index 6cb2117..bb73feb 100644 --- a/BreadPlayer.Views.UWP/Common/NotificationManager.cs +++ b/BreadPlayer.Views.UWP/Common/NotificationManager.cs @@ -9,9 +9,11 @@ using System.Threading.Tasks; using Windows.ApplicationModel.Core; using Windows.Data.Xml.Dom; +using Windows.Foundation.Metadata; using Windows.UI.Core; using Windows.UI.Notifications; using Windows.UI.Popups; +using Windows.UI.ViewManagement; using Windows.UI.Xaml; namespace BreadPlayer.NotificationManager @@ -22,7 +24,7 @@ public class BreadNotificationManager : ObservableObject, INotificationManager private ICommand _closeCommand; private DispatcherTimer _hideTimer; private string _status = string.Empty; - + private StatusBar statusBar; public ICommand CloseCommand { get => _closeCommand ?? (_closeCommand = new DelegateCommand(HideStaticMessage)); @@ -120,5 +122,23 @@ private async void HideTimer_Tick(object sender, object e) await ShowMessageAsync(NotificationQueue.Dequeue()).ConfigureAwait(false); } } + + public async Task ShowStatusBarMessageAsync(string message) + { + if (ApiInformation.IsApiContractPresent("Windows.Phone.PhoneContract", 1)) + { + await BreadDispatcher.InvokeAsync(async () => + { + if(statusBar == null) + statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView(); + await statusBar.ShowAsync(); + statusBar.ProgressIndicator.Text = message; + await statusBar.ProgressIndicator.ShowAsync(); + await Task.Delay(3000); + await statusBar.ProgressIndicator.HideAsync(); + await statusBar.HideAsync(); + }); + } + } } } \ No newline at end of file diff --git a/BreadPlayer.Views.UWP/Helpers/SettingsHelper.cs b/BreadPlayer.Views.UWP/Helpers/SettingsHelper.cs index 2a137ba..2c85448 100644 --- a/BreadPlayer.Views.UWP/Helpers/SettingsHelper.cs +++ b/BreadPlayer.Views.UWP/Helpers/SettingsHelper.cs @@ -32,7 +32,7 @@ public static T GetLocalSetting(string key, object def) public (IEqualizerSettings settings, float PreAMP) LoadEqualizerSettings(string eqConfigName) { var eqJson = GetRoamingSetting(eqConfigName, "{}"); - var settings = JsonConvert.DeserializeObject(eqJson); + var settings = JsonConvert.DeserializeObject(eqJson); return (settings, GetRoamingSetting("PreAMP", 1.0f)); } @@ -51,7 +51,7 @@ public void SaveEqualizerPresets(IEnumerable presets) public IEnumerable LoadEqualizerPresets() { - var presets = JsonConvert.DeserializeObject>(GetLocalSetting("Presets", "[]")); + var presets = JsonConvert.DeserializeObject>(GetLocalSetting("Presets", "[]")); return presets; } } diff --git a/BreadPlayer.Views.UWP/ViewModels/ShellViewModel.cs b/BreadPlayer.Views.UWP/ViewModels/ShellViewModel.cs index 11ad0fd..87d45ff 100644 --- a/BreadPlayer.Views.UWP/ViewModels/ShellViewModel.cs +++ b/BreadPlayer.Views.UWP/ViewModels/ShellViewModel.cs @@ -103,6 +103,7 @@ public ShellViewModel() PropertyChanged += ShellViewModel_PropertyChanged; SharedLogic.Instance.Player.MediaAboutToEnd += Player_MediaAboutToEnd; SharedLogic.Instance.Player.MediaChanging += OnMediaChanging; + //these events are for detecting when the default audio //device is changed in PC and Mobile. if (ApiInformation.IsApiContractPresent("Windows.Phone.PhoneContract", 1)) @@ -647,7 +648,10 @@ private Mediafile GetNextOrPrevSongInGroup(bool prev = false) //get next/prev group index int nextGroupIndex = prev ? TracksCollection.IndexOf(currentGroup) - 1 : TracksCollection.IndexOf(currentGroup) + 1; - + if (nextGroupIndex >= TracksCollection.Count - 1) + { + nextGroupIndex = 0; + } //get next/prev group. Grouping nextGroup = nextGroupCondition ? TracksCollection.ElementAt(nextGroupIndex) : currentGroup; @@ -760,8 +764,7 @@ private async void Open(object para) #region Events private int eventCount = 0; //used in AudioEndpointChangedEvent - - private void OnAudioEndpointChanged(AudioRoutingManager sender, object args) + private async void OnAudioEndpointChanged(AudioRoutingManager sender, object args) { var currentEndpoint = sender.GetAudioEndpoint(); //when this event is initialized, it is invoked 2 times. @@ -769,7 +772,7 @@ private void OnAudioEndpointChanged(AudioRoutingManager sender, object args) if (eventCount > 1) { BLogger.I($"Switching audio render device to [{currentEndpoint.ToString()}]."); - SharedLogic.Instance.Player.ChangeDevice(currentEndpoint.ToString()); + await SharedLogic.Instance.Player.ChangeDevice(currentEndpoint.ToString()); } //increase the event count eventCount += 1; diff --git a/BreadPlayer.Web/Musixmatch/HttpHelper.cs b/BreadPlayer.Web/Musixmatch/HttpHelper.cs index e297a5f..2102b63 100644 --- a/BreadPlayer.Web/Musixmatch/HttpHelper.cs +++ b/BreadPlayer.Web/Musixmatch/HttpHelper.cs @@ -16,7 +16,7 @@ public static HttpClient MusixmatchHttpClient { if (musixmatchHttpClient == null) { - musixmatchHttpClient = new HttpClient(); + musixmatchHttpClient = new HttpClient(new HttpClientHandler() { AllowAutoRedirect = false}); musixmatchHttpClient.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Musixmatch/0.19.4 Chrome/56.0.2924.87 Electron/1.6.10 Safari/537.36"); musixmatchHttpClient.DefaultRequestHeaders.AcceptEncoding.Add(new System.Net.Http.Headers.StringWithQualityHeaderValue("gzip")); } diff --git a/BreadPlayer.Web/Musixmatch/MusixmatchClient.cs b/BreadPlayer.Web/Musixmatch/MusixmatchClient.cs index cd67e18..ef1f143 100644 --- a/BreadPlayer.Web/Musixmatch/MusixmatchClient.cs +++ b/BreadPlayer.Web/Musixmatch/MusixmatchClient.cs @@ -9,31 +9,38 @@ using System.IO.Compression; using Newtonsoft.Json; using BreadPlayer.Web.Musixmatch.Models; +using RestSharp.Portable.HttpClient; +using RestSharp.Portable; namespace BreadPlayer.Web.Musixmatch { public class MusixmatchClient : ILyricAPI { public async Task FetchLyrics(Mediafile mediaFile) - { - HttpHelper.MusixmatchHttpClient.CancelPendingRequests(); - string requestURI = string.Format(@"http://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&q_track={0}&q_artist={1}&q_album={2}&user_language=en&f_subtitle_length=0&f_subtitle_length_max_deviation=0&subtitle_format=lrc&app_id=web-desktop-app-v1.0&usertoken=1710149d15ba9db2a5a545aadd4f93928e90c783ab83565d105693", mediaFile.Title, mediaFile.LeadArtist, mediaFile.Album); + { + string requestURI = string.Format(@"https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&q_track={0}&q_artist={1}&q_album={2}&user_language=en&f_subtitle_length=0&f_subtitle_length_max_deviation=0&subtitle_format=lrc&app_id=web-desktop-app-v1.0&guid=e08e6c63-edd1-4207-86dc-d350cdf7f4bc&usertoken=1710144894f79b194e5a5866d9e084d48f227d257dcd8438261277", mediaFile.Title, mediaFile.LeadArtist, mediaFile.Album); - //Send to the server - var result = await HttpHelper.MusixmatchHttpClient.GetAsync(requestURI); - if (!result.IsSuccessStatusCode) - return null; - //Read the content of the result response from the server - using (Stream stream = await result.Content.ReadAsStreamAsync()) - using (Stream decompressed = new GZipStream(stream, CompressionMode.Decompress)) - using (StreamReader reader = new StreamReader(decompressed)) + using (var client = new RestClient(requestURI)) { + var request = new RestRequest(Method.GET); + request.AddHeader("connection", "keep-alive"); + request.AddHeader("cookie", "x-mxm-user-id=; x-mxm-token-guid=e08e6c63-edd1-4207-86dc-d350cdf7f4bc; mxm-encrypted-token=; AWSELB=55578B011601B1EF8BC274C33F9043CA947F99DCFF6AB1B746DBF1E96A6F2B997493EE03F2DD5F516C3BC8E8DE7FE9C81FF414E8E76CF57330A3F26A0D86825F74794F3C94"); + request.AddHeader("cache-control", "no-cache"); + request.AddHeader("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); + request.AddHeader("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.91 Safari/537.36"); + request.AddHeader("upgrade-insecure-requests", "1"); + request.AddHeader("accept-language", "en-US,en;q=0.8"); + request.AddHeader("accept-encoding", "gzip, deflate"); + request.AddHeader("dnt", "1"); + IRestResponse response = await client.Execute(request); try { - var json = await reader.ReadToEndAsync().ConfigureAwait(false); - JsonSerializerSettings settings = new JsonSerializerSettings(); - settings.NullValueHandling = NullValueHandling.Ignore; - settings.MissingMemberHandling = MissingMemberHandling.Ignore; + var json = response.Content; + JsonSerializerSettings settings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore, + MissingMemberHandling = MissingMemberHandling.Ignore + }; var lyrics = JsonConvert.DeserializeObject(json, settings).Message?.Body?.MacroCalls?.Subtitles?.Message?.Body?.SubtitleList; if (lyrics?.Any() == true) { @@ -42,11 +49,11 @@ public async Task FetchLyrics(Mediafile mediaFile) else return null; } - catch(JsonSerializationException) + catch (JsonSerializationException) { return null; } - } + } } } } diff --git a/BreadPlayer.Web/project.json b/BreadPlayer.Web/project.json index e5c31b2..bc705be 100644 --- a/BreadPlayer.Web/project.json +++ b/BreadPlayer.Web/project.json @@ -2,6 +2,8 @@ "supports": {}, "dependencies": { "AngleSharp": "0.9.9", + "FubarCoder.RestSharp.Portable": "3.3.0", + "FubarCoder.RestSharp.Portable.HttpClient": "4.0.8", "Inflatable.Lastfm": "1.0.1.307", "LiteDB": "4.0.0", "Microsoft.NETCore.Portable.Compatibility": "1.0.1",