Prechádzať zdrojové kódy

Fix playlists bug.
Parse .bplist files.
Update version.

Stephen Damm 6 rokov pred
rodič
commit
90e8b9bd5e

+ 67 - 1
SongBrowserPlugin/DataAccess/Network/Downloader.cs

@@ -1,4 +1,5 @@
-using SongBrowserPlugin.DataAccess.BeatSaverApi;
+using SimpleJSON;
+using SongBrowserPlugin.DataAccess.BeatSaverApi;
 using SongLoaderPlugin;
 using SongLoaderPlugin.OverrideClasses;
 using System;
@@ -317,5 +318,70 @@ namespace SongBrowserPlugin
                 }
             }
         }
+
+        public void RequestSongByLevelID(string levelId, Action<Song> callback)
+        {
+            StartCoroutine(RequestSongByLevelIDCoroutine(levelId, callback));
+        }
+
+        public IEnumerator RequestSongByLevelIDCoroutine(string levelId, Action<Song> callback)
+        {
+            UnityWebRequest wwwId = UnityWebRequest.Get($"{PluginConfig.BeatsaverURL}/api/songs/search/hash/" + levelId);
+            wwwId.timeout = 10;
+
+            yield return wwwId.SendWebRequest();
+
+
+            if (wwwId.isNetworkError || wwwId.isHttpError)
+            {
+                Logger.Error(wwwId.error);
+            }
+            else
+            {
+#if DEBUG
+                Logger.Log("Received response from BeatSaver...");
+#endif
+                JSONNode node = JSON.Parse(wwwId.downloadHandler.text);
+
+                if (node["songs"].Count == 0)
+                {
+                    Logger.Error($"Song {levelId} doesn't exist on BeatSaver!");
+                    callback?.Invoke(null);
+                    yield break;
+                }
+
+                Song _tempSong = Song.FromSearchNode(node["songs"][0]);
+                callback?.Invoke(_tempSong);
+            }
+        }
+
+        public void RequestSongByKey(string key, Action<Song> callback)
+        {
+            StartCoroutine(RequestSongByKeyCoroutine(key, callback));
+        }
+
+        public IEnumerator RequestSongByKeyCoroutine(string key, Action<Song> callback)
+        {
+            UnityWebRequest wwwId = UnityWebRequest.Get($"{PluginConfig.BeatsaverURL}/api/songs/detail/" + key);
+            wwwId.timeout = 10;
+
+            yield return wwwId.SendWebRequest();
+
+
+            if (wwwId.isNetworkError || wwwId.isHttpError)
+            {
+                Logger.Error(wwwId.error);
+            }
+            else
+            {
+#if DEBUG
+                Logger.Log("Received response from BeatSaver...");
+#endif
+                JSONNode node = JSON.Parse(wwwId.downloadHandler.text);
+
+                Song _tempSong = new Song(node["song"]);
+                callback?.Invoke(_tempSong);
+            }
+        }
     }
 }

+ 1 - 0
SongBrowserPlugin/DataAccess/PlaylistReader.cs

@@ -4,6 +4,7 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
+using Logger = SongBrowserPlugin.Logging.Logger;
 
 namespace SongBrowserPlugin.DataAccess
 {

+ 1 - 0
SongBrowserPlugin/DataAccess/PlaylistWriter.cs

@@ -2,6 +2,7 @@
 using SongBrowserPlugin.Logging;
 using System;
 using System.IO;
+using Logger = SongBrowserPlugin.Logging.Logger;
 
 namespace SongBrowserPlugin.DataAccess
 {

+ 1 - 1
SongBrowserPlugin/DataAccess/ScoreSaberDatabase.cs

@@ -3,7 +3,7 @@ using SongBrowserPlugin.Logging;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
-
+using Logger = SongBrowserPlugin.Logging.Logger;
 
 namespace SongBrowserPlugin.DataAccess
 {

+ 1 - 0
SongBrowserPlugin/DataAccess/SongBrowserSettings.cs

@@ -6,6 +6,7 @@ using System.Text;
 using System.Xml;
 using System.Xml.Serialization;
 using SongBrowserPlugin.Logging;
+using Logger = SongBrowserPlugin.Logging.Logger;
 
 namespace SongBrowserPlugin.DataAccess
 {

+ 1 - 1
SongBrowserPlugin/Plugin.cs

@@ -8,7 +8,7 @@ namespace SongBrowserPlugin
 {
     public class Plugin : IPlugin
     {
-        public const string VERSION_NUMBER = "v2.4.4";
+        public const string VERSION_NUMBER = "v2.4.5";
 
         public string Name
         {

+ 1 - 3
SongBrowserPlugin/UI/Browser/SongBrowserUI.cs

@@ -167,6 +167,7 @@ namespace SongBrowserPlugin.UI
                 if (_playListFlowCoordinator == null)
                 {
                     _playListFlowCoordinator = UIBuilder.CreateFlowCoordinator<PlaylistFlowCoordinator>("PlaylistFlowCoordinator");
+                    _playListFlowCoordinator.didFinishEvent += HandleDidSelectPlaylist;
                 }
 
                 // delete dialog
@@ -518,9 +519,6 @@ namespace SongBrowserPlugin.UI
             if (_model.Settings.filterMode != SongFilterMode.Playlist)
             {
                 _playListFlowCoordinator.ParentFlowCoordinator = _levelSelectionFlowCoordinator;
-                _playListFlowCoordinator.didFinishEvent -= HandleDidSelectPlaylist;
-                _playListFlowCoordinator.didFinishEvent += HandleDidSelectPlaylist;
-
                 _levelSelectionFlowCoordinator.InvokePrivateMethod("PresentFlowCoordinator", new object[] { _playListFlowCoordinator, null, false, false });                                
             }
             else

+ 2 - 2
SongBrowserPlugin/UI/DownloadQueue/DownloadQueueViewController.cs

@@ -114,7 +114,7 @@ namespace SongBrowserPlugin.UI.DownloadQueue
             song.songQueueState = SongQueueState.Queued;
             if (startDownload && queuedSongs.Count(x => x.songQueueState == SongQueueState.Downloading) < PluginConfig.MaxSimultaneousDownloads)
             {
-                DownloadSong(song);
+                StartCoroutine(DownloadSong(song));
             }
             Refresh();
         }
@@ -125,7 +125,7 @@ namespace SongBrowserPlugin.UI.DownloadQueue
 
             for (int i = 0; i < Math.Min(PluginConfig.MaxSimultaneousDownloads, queuedSongs.Count); i++)
             {
-                DownloadSong(queuedSongs[i]);
+                StartCoroutine(DownloadSong(queuedSongs[i]));
             }
         }
 

+ 86 - 185
SongBrowserPlugin/UI/Playlists/PlaylistFlowCoordinator.cs

@@ -18,62 +18,41 @@ namespace SongBrowserPlugin.UI
 {
     public class PlaylistFlowCoordinator : FlowCoordinator
     {
-        private BackButtonNavigationController _playlistNavigationController;
-        private PlaylistListViewController _playlistListViewController;
-        private PlaylistDetailViewController _playlistDetailViewController;
-
-        public DownloadQueueViewController DownloadQueueViewController;
+        public event Action<Playlist> didFinishEvent;
 
         public FlowCoordinator ParentFlowCoordinator;
 
-        public PlaylistsReader _playlistsReader;
+        private BackButtonNavigationController _playlistsNavigationController;
+        private PlaylistListViewController _playlistListViewController;
+        private PlaylistDetailViewController _playlistDetailViewController;
+        private DownloadQueueViewController _downloadQueueViewController;
 
         private bool _downloadingPlaylist;
 
+        private PlaylistsReader _playlistsReader;
         private Playlist _lastPlaylist;
 
-        /// <summary>
-        /// User pressed "select" on the playlist.
-        /// </summary>
-        public Action<Playlist> didFinishEvent;
-
-        /// <summary>
-        /// Destroy.
-        /// </summary>
-        public virtual void OnDestroy()
-        {
-            Logger.Trace("OnDestroy()");
-        }
-
-        /// <summary>
-        /// 
-        /// </summary>
         public void Awake()
         {
-            if (_playlistNavigationController == null)
+            if (_playlistsNavigationController == null)
             {
-                _playlistNavigationController = BeatSaberUI.CreateViewController<BackButtonNavigationController>();
+                _playlistsNavigationController = BeatSaberUI.CreateViewController<BackButtonNavigationController>();
 
-                GameObject _playlistDetailGameObject = Instantiate(Resources.FindObjectsOfTypeAll<StandardLevelDetailViewController>().First(), _playlistNavigationController.rectTransform, false).gameObject;
+                GameObject _playlistDetailGameObject = Instantiate(Resources.FindObjectsOfTypeAll<StandardLevelDetailViewController>().First(), _playlistsNavigationController.rectTransform, false).gameObject;
                 _playlistDetailViewController = _playlistDetailGameObject.AddComponent<PlaylistDetailViewController>();
                 Destroy(_playlistDetailGameObject.GetComponent<StandardLevelDetailViewController>());
                 _playlistDetailViewController.name = "PlaylistDetailViewController";
             }
         }
 
-        /// <summary>
-        /// Present the playlist selector flow.
-        /// </summary>
-        /// <param name="parentViewController"></param>
-        /// <param name="levels"></param>
-        /// <param name="gameplayMode"></param>
         protected override void DidActivate(bool firstActivation, ActivationType activationType)
         {
-            Logger.Trace("Presenting Playlist Selector! - firstActivation: {0}", firstActivation);
             try
             {
                 if (firstActivation && activationType == ActivationType.AddedToHierarchy)
                 {
+                    title = "Playlists";
+
                     if (_playlistsReader == null)
                     {
                         _playlistsReader = new PlaylistsReader();
@@ -83,188 +62,80 @@ namespace SongBrowserPlugin.UI
                         this.MatchSongsForAllPlaylists(true);
                     }
 
-                    title = "Playlists";
-
-                    _playlistNavigationController.didFinishEvent += HandleDidDismiss;
+                    _playlistsNavigationController.didFinishEvent += _playlistsNavigationController_didFinishEvent;
 
                     _playlistListViewController = BeatSaberUI.CreateViewController<PlaylistListViewController>();
-                    _playlistListViewController.didSelectRow += HandleSelectRow;
+                    _playlistListViewController.didSelectRow += _playlistListViewController_didSelectRow;
 
-                    _playlistDetailViewController.downloadButtonPressed += HandleDownloadPressed;
-                    _playlistDetailViewController.selectButtonPressed += HandleDidSelectPlaylist;
+                    _playlistDetailViewController.downloadButtonPressed += _playlistDetailViewController_downloadButtonPressed;
+                    _playlistDetailViewController.selectButtonPressed += _playlistDetailViewController_selectButtonPressed;
 
-                    DownloadQueueViewController = BeatSaberUI.CreateViewController<DownloadQueueViewController>();
+                    _downloadQueueViewController = BeatSaberUI.CreateViewController<DownloadQueueViewController>();
 
-                    SetViewControllersToNavigationConctroller(_playlistNavigationController, new VRUIViewController[]
+                    SetViewControllersToNavigationConctroller(_playlistsNavigationController, new VRUIViewController[]
                     {
                         _playlistListViewController
                     });
 
-                    ProvideInitialViewControllers(_playlistNavigationController, DownloadQueueViewController, null);
+                    ProvideInitialViewControllers(_playlistsNavigationController, _downloadQueueViewController, null);
                 }
-
                 _downloadingPlaylist = false;
                 _playlistListViewController.SetContent(_playlistsReader.Playlists);
 
-                DownloadQueueViewController.allSongsDownloaded += HandleAllSongsDownloaded;
+                _downloadQueueViewController.allSongsDownloaded += _downloadQueueViewController_allSongsDownloaded;
             }
             catch (Exception e)
             {
-                Logger.Exception("Exception displaying playlist selector", e);
+                Logger.Exception("Error activating playlist flow coordinator: ", e);
             }
         }
 
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="deactivationType"></param>
         protected override void DidDeactivate(DeactivationType deactivationType)
         {
-            DownloadQueueViewController.allSongsDownloaded -= HandleAllSongsDownloaded;
+            _downloadQueueViewController.allSongsDownloaded -= _downloadQueueViewController_allSongsDownloaded;
+
         }
 
-        /// <summary>
-        /// Update the playlist detail view when a row is selected.
-        /// </summary>
-        /// <param name="songListViewController"></param>
-        public virtual void HandleSelectRow(Playlist playlist)
+        private void _downloadQueueViewController_allSongsDownloaded()
         {
-            Logger.Debug("Selected Playlist: {0}", playlist.Title);
-
-            //int missingCount = CountMissingSongs(playlist);
+            SongLoader.Instance.RefreshSongs(false);
+            _downloadingPlaylist = false;
+        }
 
+        private void _playlistListViewController_didSelectRow(Playlist playlist)
+        {
             if (!_playlistDetailViewController.isInViewControllerHierarchy)
             {
-                PushViewControllerToNavigationController(_playlistNavigationController, _playlistDetailViewController);
+                PushViewControllerToNavigationController(_playlistsNavigationController, _playlistDetailViewController);
             }
 
             _lastPlaylist = playlist;
             _playlistDetailViewController.SetContent(playlist);
-
-            this._playlistDetailViewController.UpdateButtons(!_downloadingPlaylist, !_downloadingPlaylist);
-        }
-
-        /// <summary>
-        /// Playlist was selected, dismiss view and inform song browser.
-        /// </summary>
-        /// <param name="p"></param>
-        public void HandleDidSelectPlaylist(Playlist p)
-        {
-            try
-            {
-                if (!DownloadQueueViewController.queuedSongs.Any(x => x.songQueueState == SongQueueState.Downloading || x.songQueueState == SongQueueState.Queued))
-                {
-                    DownloadQueueViewController.AbortDownloads();
-
-                    if (_playlistNavigationController.viewControllers.IndexOf(_playlistDetailViewController) >= 0)
-                    {
-                        PopViewControllerFromNavigationController(_playlistNavigationController, null, true);
-                    }
-
-                    ParentFlowCoordinator.InvokePrivateMethod("DismissFlowCoordinator", new object[] { this, null, false });
-                    didFinishEvent?.Invoke(p);
-                }
-            }
-            catch (Exception e)
-            {
-                Logger.Exception("", e);
-            }
         }
 
-        /// <summary>
-        /// Playlist was dismissed, inform song browser (pass in null).
-        /// </summary>
-        public void HandleDidDismiss()
+        private void _playlistDetailViewController_selectButtonPressed(Playlist playlist)
         {
-            try
+            if (!_downloadQueueViewController.queuedSongs.Any(x => x.songQueueState == SongQueueState.Downloading || x.songQueueState == SongQueueState.Queued))
             {
-                if (!DownloadQueueViewController.queuedSongs.Any(x => x.songQueueState == SongQueueState.Downloading || x.songQueueState == SongQueueState.Queued))
+                if (_playlistsNavigationController.viewControllers.IndexOf(_playlistDetailViewController) >= 0)
                 {
-                    DownloadQueueViewController.AbortDownloads();
-                    SongLoader.Instance.RefreshSongs(false);
-
-                    if (_playlistNavigationController.viewControllers.IndexOf(_playlistDetailViewController) >= 0)
-                    {
-                        PopViewControllerFromNavigationController(_playlistNavigationController, null, true);
-                    }
-
-                    ParentFlowCoordinator.InvokePrivateMethod("DismissFlowCoordinator", new object[] { this, null, false });
-                    didFinishEvent?.Invoke(null);
+                    PopViewControllerFromNavigationController(_playlistsNavigationController, null, true);
                 }
-            }
-            catch (Exception e)
-            {
-                Logger.Exception("", e);
-            }
-        }
-
-        /// <summary>
-        /// Filter songs that we don't have data for.
-        /// </summary>
-        /// <param name="songs"></param>
-        /// <param name="playlist"></param>
-        /// <returns></returns>
-        private void FilterSongsForPlaylist(Playlist playlist, bool matchAll = false)
-        {
-            if (!playlist.Songs.All(x => x.Level != null) || matchAll)
-            {
-                playlist.Songs.ForEach(x =>
-                {
-                    if (x.Level == null || matchAll)
-                    {
-                        x.Level = SongLoader.CustomLevels.FirstOrDefault(y => (y.customSongInfo.path.Contains(x.Key) && Directory.Exists(y.customSongInfo.path)) || (string.IsNullOrEmpty(x.LevelId) ? false : y.levelID.StartsWith(x.LevelId)));
-                    }
-                });
-            }
-        }
 
-        /// <summary>
-        /// 
-        /// </summary>
-        /// <param name="matchAll"></param>
-        public void MatchSongsForAllPlaylists(bool matchAll = false)
-        {
-            Logger.Info("Matching songs for all playlists!");
-            foreach (Playlist playlist in _playlistsReader.Playlists)
-            {
-                FilterSongsForPlaylist(playlist, matchAll);
+                ParentFlowCoordinator.InvokePrivateMethod("DismissFlowCoordinator", new object[] { this, null, false });
+                didFinishEvent?.Invoke(playlist);
             }
         }
 
-        /// <summary>
-        /// Count missing songs for display.
-        /// </summary>
-        /// <param name="playlist"></param>
-        /// <returns></returns>
-        private int CountMissingSongs(Playlist playlist)
-        {
-            return playlist.Songs.Count - playlist.Songs.Count(x => SongLoader.CustomLevels.Any(y => y.customSongInfo.path.Contains(x.Key)));
-        }
-
-        /// <summary>
-        /// Download playlist button pressed.
-        /// </summary>
-        private void HandleDownloadPressed(Playlist playlist)
+        private void _playlistDetailViewController_downloadButtonPressed(Playlist playlist)
         {
             if (!_downloadingPlaylist)
-            {
                 StartCoroutine(DownloadPlaylist(playlist));
-            }
-            else
-            {
-                Logger.Info("Already downloading playlist!");
-            }
         }
 
-        /// <summary>
-        /// Download Playlist.
-        /// </summary>
-        /// <param name="playlist"></param>
-        /// <returns></returns>
         public IEnumerator DownloadPlaylist(Playlist playlist)
         {
-            this.FilterSongsForPlaylist(playlist, true);
-            List<PlaylistSong> playlistSongsToDownload = playlist.Songs.Where(x => x.Level == null).ToList();
+            PlaylistFlowCoordinator.MatchSongsForPlaylist(playlist, true);
 
             List<PlaylistSong> needToDownload = playlist.Songs.Where(x => x.Level == null).ToList();
             Logger.Info($"Need to download {needToDownload.Count} songs");
@@ -295,19 +166,12 @@ namespace SongBrowserPlugin.UI
 
                 if (beatSaverSong != null && !SongLoader.CustomLevels.Any(x => x.levelID.Substring(0, 32) == beatSaverSong.hash.ToUpper()))
                 {
-                    DownloadQueueViewController.EnqueueSong(beatSaverSong, true);
+                    _downloadQueueViewController.EnqueueSong(beatSaverSong, true);
                 }
             }
             _downloadingPlaylist = false;
         }
 
-        /// <summary>
-        /// Request song info via BeatSaber (or custom) api call.
-        /// </summary>
-        /// <param name="playlist"></param>
-        /// <param name="song"></param>
-        /// <param name="songCallback"></param>
-        /// <returns></returns>
         public IEnumerator GetInfoForSong(Playlist playlist, PlaylistSong song, Action<Song> songCallback)
         {
             string url = $"{PluginConfig.BeatsaverURL}/api/songs/detail/{song.Key}";
@@ -316,7 +180,6 @@ namespace SongBrowserPlugin.UI
                 url = playlist.CustomDetailUrl + song.Key;
             }
 
-            Logger.Debug("Attempting to connect to: {0}", url);
             UnityWebRequest www = UnityWebRequest.Get(url);
             www.timeout = 15;
             yield return www.SendWebRequest();
@@ -339,17 +202,55 @@ namespace SongBrowserPlugin.UI
             }
         }
 
+        private void _playlistsNavigationController_didFinishEvent()
+        {
+            if (!_downloadQueueViewController.queuedSongs.Any(x => x.songQueueState == SongQueueState.Downloading || x.songQueueState == SongQueueState.Queued))
+            {
+                if (_downloadQueueViewController.queuedSongs.Any(x => x.songQueueState == SongQueueState.Downloading || x.songQueueState == SongQueueState.Queued))
+                    _downloadQueueViewController.AbortDownloads();
+
+                if (_playlistsNavigationController.viewControllers.IndexOf(_playlistDetailViewController) >= 0)
+                {
+                    PopViewControllerFromNavigationController(_playlistsNavigationController, null, true);
+                }
+
+                ParentFlowCoordinator.InvokePrivateMethod("DismissFlowCoordinator", new object[] { this, null, false });
+                didFinishEvent?.Invoke(null);
+            }
+        }
+
         /// <summary>
-        /// Songs finished downloading.
+        /// 
         /// </summary>
-        private void HandleAllSongsDownloaded()
+        /// <param name="playlist"></param>
+        /// <param name="matchAll"></param>
+        public static void MatchSongsForPlaylist(Playlist playlist, bool matchAll = false)
         {
-            SongLoader.Instance.RefreshSongs(false);
-
-            this.FilterSongsForPlaylist(_lastPlaylist, true);
+            if (!SongLoader.AreSongsLoaded || SongLoader.AreSongsLoading || playlist.Title == "All songs" || playlist.Title == "Your favorite songs") return;
+            if (!playlist.Songs.All(x => x.Level != null) || matchAll)
+            {
+                playlist.Songs.ForEach(x =>
+                {
+                    if (x.Level == null || matchAll)
+                    {
+                        x.Level = SongLoader.CustomLevels.FirstOrDefault(y => (y.customSongInfo.path.Contains(x.Key) && Directory.Exists(y.customSongInfo.path)) || (string.IsNullOrEmpty(x.LevelId) ? false : y.levelID.StartsWith(x.LevelId)));
+                    }
+                });
+            }
+        }
 
-            _downloadingPlaylist = false;
-            _playlistDetailViewController.UpdateButtons(!_downloadingPlaylist, !_downloadingPlaylist);
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="matchAll"></param>
+        public void MatchSongsForAllPlaylists(bool matchAll = false)
+        {
+            Logger.Info("Matching songs for all playlists!");
+            foreach (Playlist playlist in _playlistsReader.Playlists)
+            {
+                MatchSongsForPlaylist(playlist, matchAll);
+            }
+            Logger.Info("Done matching songs for all playlists...");
         }
 
         /// <summary>
@@ -363,17 +264,17 @@ namespace SongBrowserPlugin.UI
 
             if (isShiftKeyDown && Input.GetKeyDown(KeyCode.Return))
             {
-                HandleDownloadPressed(_lastPlaylist);
+                _playlistDetailViewController_downloadButtonPressed(_lastPlaylist);
             }
             else if (Input.GetKeyDown(KeyCode.Return))
             {
-                HandleDidSelectPlaylist(_lastPlaylist);
+                _playlistDetailViewController_selectButtonPressed(_lastPlaylist);
             }
 
             // leave
             if (Input.GetKeyDown(KeyCode.Escape))
             {
-                HandleDidDismiss();
+                _playlistsNavigationController_didFinishEvent();
             }
         }
     }

+ 4 - 2
SongBrowserPlugin/UI/Playlists/PlaylistSelectionListViewController.cs

@@ -100,7 +100,7 @@ namespace SongBrowserPlugin.UI
             _lastSelectedRow = -1;
         }
 
-        public void SetContent(List<Playlist> playlists, Playlist select = null)
+        public void SetContent(List<Playlist> playlists)
         {
             if (playlists == null && playlistList != null)
                 playlistList.Clear();
@@ -138,7 +138,9 @@ namespace SongBrowserPlugin.UI
             _tableCell.reuseIdentifier = "PlaylistTableCell";
             _tableCell.songName = playlistList[row].Title;
             _tableCell.author = playlistList[row].Author;
-            _tableCell.coverImage = Base64Sprites.Base64ToSprite(playlistList[row].Image);
+
+            if (playlistList[row].Image != null)
+                _tableCell.coverImage = Base64Sprites.Base64ToSprite(playlistList[row].Image);
 
             return _tableCell;
         }