瀏覽代碼

Fix playlist and song downloading.
Bring in fixes from Downloader.
Remove dead file.

Stephen Damm 5 年之前
父節點
當前提交
9b500d75c1

+ 147 - 136
SongBrowserPlugin/DataAccess/BeatSaverApi/BeatSaverApiResults.cs

@@ -1,62 +1,77 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using SimpleJSON;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
 
 namespace SongBrowser.DataAccess.BeatSaverApi
 {
     public enum SongQueueState { Queued, Downloading, Downloaded, Error };
-
     [Serializable]
-    public class DifficultyLevel
+    public class Metadata
     {
-        public string difficulty;
-        public int difficultyRank;
-        public string jsonPath;
-        public int? offset;
-
-        //bananbread api
-        //      public DifficultyLevel(CustomSongInfo.DifficultyLevel difficultyLevel)
-        //      {
-        //          difficulty = difficultyLevel.difficulty;
-        //          difficultyRank = difficultyLevel.difficultyRank;
-        //          jsonPath = difficultyLevel.jsonPath;
-        //      }
+        public string[] characteristics;
+        public Difficulties difficulties;
 
-        public DifficultyLevel(string Difficulty, int DifficultyRank, string JsonPath, int Offset = 0)
+        public Metadata()
         {
-            difficulty = Difficulty;
-            difficultyRank = DifficultyRank;
-            jsonPath = JsonPath;
-            offset = Offset;
+        }
 
+        [JsonConstructor]
+        public Metadata(string[] characteristics, Difficulties difficulties)
+        {
+            this.characteristics = characteristics;
+            this.difficulties = difficulties;
         }
 
+        [Serializable]
+        public class Difficulties
+        {
+            public bool easy = false;
+            public bool normal = false;
+            public bool hard = false;
+            public bool expert = false;
+            public bool expertPlus = false;
+            [JsonConstructor]
+            public Difficulties(bool easy, bool normal, bool hard, bool expert, bool expertPlus)
+            {
+                this.easy = easy;
+                this.normal = normal;
+                this.hard = hard;
+                this.expert = expert;
+                this.expertPlus = expertPlus;
+            }
+
+        }
     }
     [Serializable]
     public class Song
     {
-        public string id;
-        public string beatname;
-        public string ownerid;
-        public string downloads;
-        public string upvotes;
-        public string plays;
-        public string description;
-        public string uploadtime;
+        public Metadata metadata;
+        public string levelAuthorName;
+        public string songAuthorName;
         public string songName;
         public string songSubName;
-        public string authorName;
-        public string beatsPerMinute;
-        public string downvotes;
-        public string coverUrl;
-        public string downloadUrl;
-        public DifficultyLevel[] difficultyLevels;
-        public string img;
+        public float bpm;
+        public int downloads;
+        public int plays;
+        public int upVotes;
+        public int downVotes;
+        public float rating;
+        public float heat;
+        public string description;
+        public string _id;
+        public string key;
+        public string name;
+        public string ownerid;
+        public string ownerName;
         public string hash;
+        public string uploaded;
+        public string downloadURL;
+        public string coverURL;
+        public string img;
+
 
         public string path;
+        public bool scoreSaber;
 
         public SongQueueState songQueueState = SongQueueState.Queued;
 
@@ -67,112 +82,101 @@ namespace SongBrowser.DataAccess.BeatSaverApi
 
         }
 
-        public Song(JSONNode jsonNode)
+        public Song(JObject jsonNode, bool scoreSaber)
         {
-            id = jsonNode["key"];
-            beatname = jsonNode["name"];
-            ownerid = jsonNode["uploaderId"];
-            downloads = jsonNode["downloadCount"];
-            upvotes = jsonNode["upVotes"];
-            downvotes = jsonNode["downVotes"];
-            plays = jsonNode["playedCount"];
-            description = jsonNode["description"];
-            uploadtime = jsonNode["createdAt"];
-            songName = jsonNode["songName"];
-            songSubName = jsonNode["songSubName"];
-            authorName = jsonNode["authorName"];
-            beatsPerMinute = jsonNode["bpm"];
-            coverUrl = jsonNode["coverUrl"];
-            downloadUrl = jsonNode["downloadUrl"];
-            hash = jsonNode["hashMd5"];
-            hash = hash.ToUpper();
-
-            var difficultyNode = jsonNode["difficulties"];
-
-            difficultyLevels = new DifficultyLevel[difficultyNode.Count];
-
-            for (int i = 0; i < difficultyNode.Count; i++)
+            if (scoreSaber)
             {
-                difficultyLevels[i] = new DifficultyLevel(difficultyNode[i]["difficulty"], difficultyNode[i]["difficultyRank"], difficultyNode[i]["audioPath"], difficultyNode[i]["jsonPath"]);
+                this.scoreSaber = scoreSaber;
+                ConstructFromScoreSaber(jsonNode);
+                return;
             }
+            metadata = jsonNode["metadata"].ToObject<Metadata>();
+            levelAuthorName = (string)jsonNode["metadata"]["levelAuthorName"];
+            songAuthorName = (string)jsonNode["metadata"]["songAuthorName"];
+            songName = (string)jsonNode["metadata"]["songName"];
+            songSubName = (string)jsonNode["metadata"]["songSubName"];
+            bpm = (float)jsonNode["metadata"]["bpm"];
+            downloads = (int)jsonNode["stats"]["downloads"];
+            plays = (int)jsonNode["stats"]["plays"];
+            upVotes = (int)jsonNode["stats"]["upVotes"];
+            downVotes = (int)jsonNode["stats"]["downVotes"];
+            rating = (float)jsonNode["stats"]["rating"];
+            heat = (float)jsonNode["stats"]["heat"];
+            description = (string)jsonNode["description"];
+            _id = (string)jsonNode["_id"];
+            key = (string)jsonNode["key"];
+            name = (string)jsonNode["name"];
+            ownerid = (string)jsonNode["uploader"]["_id"];
+            ownerName = (string)jsonNode["uploader"]["username"];
+            hash = (string)jsonNode["hash"];
+            hash = hash.ToLower();
+            uploaded = (string)jsonNode["uploaded"];
+            downloadURL = PluginConfig.beatsaverURL + (string)jsonNode["downloadURL"];
+            coverURL = PluginConfig.beatsaverURL + (string)jsonNode["coverURL"];
         }
 
-        public static Song FromSearchNode(JSONNode mainNode)
+        public void ConstructFromScoreSaber(JObject jsonNode)
         {
-            Song buffer = new Song();
-            buffer.id = mainNode["key"];
-            buffer.beatname = mainNode["name"];
-            buffer.ownerid = mainNode["uploaderId"];
-            buffer.downloads = mainNode["downloadCount"];
-            buffer.upvotes = mainNode["upVotes"];
-            buffer.downvotes = mainNode["downVotes"];
-            buffer.plays = mainNode["playedCount"];
-            buffer.uploadtime = mainNode["createdAt"];
-            buffer.songName = mainNode["songName"];
-            buffer.songSubName = mainNode["songSubName"];
-            buffer.authorName = mainNode["authorName"];
-            buffer.beatsPerMinute = mainNode["bpm"];
-            buffer.coverUrl = mainNode["coverUrl"];
-            buffer.downloadUrl = mainNode["downloadUrl"];
-            buffer.hash = mainNode["hashMd5"];
-
-            var difficultyNode = mainNode["difficulties"];
-
-            buffer.difficultyLevels = new DifficultyLevel[difficultyNode.Count];
-
-            for (int i = 0; i < difficultyNode.Count; i++)
-            {
-                buffer.difficultyLevels[i] = new DifficultyLevel(difficultyNode[i]["difficulty"], difficultyNode[i]["difficultyRank"], difficultyNode[i]["audioPath"], difficultyNode[i]["jsonPath"]);
-            }
-
-            return buffer;
+            _id = "";
+            ownerid = "";
+            downloads = 0;
+            upVotes = 0;
+            downVotes = 0;
+            plays = 0;
+            description = "";
+            uploaded = "";
+            rating = 0;
+            heat = 0f;
+            key = "";
+            name = "";
+            ownerName = "";
+            downloadURL = "";
+            songName = (string)jsonNode["name"];
+            songSubName = (string)jsonNode["songSubName"];
+            levelAuthorName = (string)jsonNode["levelAuthorName"];
+            songAuthorName = (string)jsonNode["songAuthorName"];
+            bpm = (int)jsonNode["bpm"];
+            coverURL = PluginConfig.scoresaberURL + jsonNode["image"];
+            hash = (string)jsonNode["id"];
+            hash = hash.ToLower();
+            metadata = new Metadata() { characteristics = new string[] { "Standard" }, difficulties = new Metadata.Difficulties(true, false, false, false, false) };
+            //       difficultyLevels = new DifficultyLevel[1];
+            //       difficultyLevels[0] = new DifficultyLevel("Easy", 4, "", 0);
         }
 
-        public Song(JSONNode jsonNode, JSONNode difficultyNode)
+        public static Song FromSearchNode(JObject jsonNode)
         {
-
-            id = jsonNode["key"];
-            beatname = jsonNode["name"];
-            ownerid = jsonNode["uploaderId"];
-            downloads = jsonNode["downloadCount"];
-            upvotes = jsonNode["upVotes"];
-            downvotes = jsonNode["downVotes"];
-            plays = jsonNode["playedCount"];
-            description = jsonNode["description"];
-            uploadtime = jsonNode["createdAt"];
-            songName = jsonNode["songName"];
-            songSubName = jsonNode["songSubName"];
-            authorName = jsonNode["authorName"];
-            beatsPerMinute = jsonNode["bpm"];
-            coverUrl = jsonNode["coverUrl"];
-            downloadUrl = jsonNode["downloadUrl"];
-            hash = jsonNode["hashMd5"];
-
-            difficultyLevels = new DifficultyLevel[difficultyNode.Count];
-
-            for (int i = 0; i < difficultyNode.Count; i++)
-            {
-                difficultyLevels[i] = new DifficultyLevel(difficultyNode[i]["difficulty"], difficultyNode[i]["difficultyRank"], difficultyNode[i]["audioPath"], difficultyNode[i]["jsonPath"]);
-            }
+            Song buffer = new Song();
+            buffer.metadata = jsonNode["metadata"].ToObject<Metadata>();
+            buffer.levelAuthorName = (string)jsonNode["metadata"]["levelAuthorName"];
+            buffer.songAuthorName = (string)jsonNode["metadata"]["songAuthorName"];
+            buffer.songName = (string)jsonNode["metadata"]["songName"];
+            buffer.songSubName = (string)jsonNode["metadata"]["songSubName"];
+            buffer.bpm = (float)jsonNode["metadata"]["bpm"];
+            buffer.downloads = (int)jsonNode["stats"]["downloads"];
+            buffer.plays = (int)jsonNode["stats"]["plays"];
+            buffer.upVotes = (int)jsonNode["stats"]["upVotes"];
+            buffer.downVotes = (int)jsonNode["stats"]["downVotes"];
+            buffer.rating = (float)jsonNode["stats"]["rating"];
+            buffer.heat = (float)jsonNode["stats"]["heat"];
+            buffer.description = (string)jsonNode["description"];
+            buffer._id = (string)jsonNode["_id"];
+            buffer.key = (string)jsonNode["key"];
+            buffer.name = (string)jsonNode["name"];
+            buffer.ownerid = (string)jsonNode["uploader"]["_id"];
+            buffer.ownerName = (string)jsonNode["uploader"]["username"];
+            buffer.hash = (string)jsonNode["hash"];
+            buffer.hash = buffer.hash.ToLower();
+            buffer.uploaded = (string)jsonNode["uploaded"];
+            buffer.downloadURL = PluginConfig.beatsaverURL + (string)jsonNode["downloadURL"];
+            buffer.coverURL = PluginConfig.beatsaverURL + (string)jsonNode["coverURL"];
+            return buffer;
         }
 
+
         public bool Compare(Song compareTo)
         {
-            if (compareTo != null && songName == compareTo.songName)
-            {
-                if (difficultyLevels != null && compareTo.difficultyLevels != null)
-                {
-                    return (songSubName == compareTo.songSubName && authorName == compareTo.authorName && difficultyLevels.Length == compareTo.difficultyLevels.Length);
-                }
-                else
-                {
-                    return (songSubName == compareTo.songSubName && authorName == compareTo.authorName);
-                }
-            }
-            else
-            {
-                return false;
-            }
+            return compareTo.hash == hash;
         }
 
 
@@ -181,11 +185,12 @@ namespace SongBrowser.DataAccess.BeatSaverApi
         {
             songName = _data.songName;
             songSubName = _data.songSubName;
-            authorName = _data.songAuthorName;
-            difficultyLevels = ConvertDifficultyLevels(_data.standardLevelInfoSaveData.difficultyBeatmapSets.SelectMany(x => x.difficultyBeatmaps).ToArray());
+            songAuthorName = _data.songAuthorName;
+            levelAuthorName = _data.levelAuthorName;
+            //   difficultyLevels = ConvertDifficultyLevels(_data.standardLevelInfoSaveData.difficultyBeatmapSets.SelectMany(x => x.difficultyBeatmaps).ToArray());
             path = _data.customLevelPath;
             //bananabread id hash
-            hash = SongCore.Collections.hashForLevelID(_data.levelID);
+            hash = SongCore.Collections.hashForLevelID(_data.levelID).ToLower();
             //  hash = SongCore.Utilities.Utils.GetCustomLevelHash(_data);
         }
         /*
@@ -214,6 +219,7 @@ namespace SongBrowser.DataAccess.BeatSaverApi
         //bananbread api
         public Song(CustomSongInfo _song)
         {
+
             songName = _song.songName;
             songSubName = _song.songSubName;
             authorName = _song.songAuthorName;
@@ -229,10 +235,13 @@ namespace SongBrowser.DataAccess.BeatSaverApi
             if (_difficultyLevels != null && _difficultyLevels.Length > 0)
             {
                 DifficultyLevel[] buffer = new DifficultyLevel[_difficultyLevels.Length];
+
                 for (int i = 0; i < _difficultyLevels.Length; i++)
                 {
                     buffer[i] = new DifficultyLevel(_difficultyLevels[i]);
                 }
+
+
                 return buffer;
             }
             else
@@ -241,7 +250,7 @@ namespace SongBrowser.DataAccess.BeatSaverApi
             }
         }
         */
-
+        /*
         public DifficultyLevel[] ConvertDifficultyLevels(IDifficultyBeatmap[] _difficultyLevels)
         {
             if (_difficultyLevels != null && _difficultyLevels.Length > 0)
@@ -261,6 +270,8 @@ namespace SongBrowser.DataAccess.BeatSaverApi
                 return null;
             }
         }
+        */
+        /*
         public DifficultyLevel[] ConvertDifficultyLevels(StandardLevelInfoSaveData.DifficultyBeatmap[] _difficultyLevels)
         {
             if (_difficultyLevels != null && _difficultyLevels.Length > 0)
@@ -280,7 +291,7 @@ namespace SongBrowser.DataAccess.BeatSaverApi
                 return null;
             }
         }
-
+        */
     }
     [Serializable]
     public class RootObject

+ 65 - 25
SongBrowserPlugin/DataAccess/Network/Downloader.cs

@@ -1,7 +1,4 @@
-using SimpleJSON;
-using SongBrowser.DataAccess;
-using SongBrowser.DataAccess.BeatSaverApi;
-using System;
+using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.IO;
@@ -13,11 +10,13 @@ using System.Threading;
 using System.Threading.Tasks;
 using UnityEngine;
 using UnityEngine.Networking;
+using Newtonsoft.Json.Linq;
 using Logger = SongBrowser.Logging.Logger;
+using SongBrowser.DataAccess.BeatSaverApi;
+using SongBrowser.DataAccess;
 
 namespace SongBrowser
 {
-    // https://github.com/andruzzzhka/BeatSaverDownloader/blob/master/BeatSaverDownloader/Misc/SongDownloader.cs
     public class SongDownloader : MonoBehaviour
     {
         public event Action<Song> songDownloaded;
@@ -58,7 +57,7 @@ namespace SongBrowser
 
         private void SongLoader_SongsLoadedEvent(SongCore.Loader sender, Dictionary<string, CustomPreviewBeatmapLevel> levels)
         {
-            _alreadyDownloadedSongs = levels.Select(x => new Song(x.Value)).ToList();
+            _alreadyDownloadedSongs = levels.Values.Select(x => new Song(x)).ToList();
         }
 
         public IEnumerator DownloadSongCoroutine(Song songInfo)
@@ -72,7 +71,7 @@ namespace SongBrowser
 
             try
             {
-                www = UnityWebRequest.Get(songInfo.downloadUrl);
+                www = UnityWebRequest.Get(songInfo.downloadURL);
 
                 asyncRequest = www.SendWebRequest();
             }
@@ -150,8 +149,16 @@ namespace SongBrowser
                 Logger.Info("Extracting...");
                 _extractingZip = true;
                 ZipArchive archive = new ZipArchive(zipStream, ZipArchiveMode.Read);
-                await Task.Run(() => archive.ExtractToDirectory(customSongsPath)).ConfigureAwait(false);
+                string path = customSongsPath + "/" + songInfo.key + " (" + songInfo.songName + " - " + songInfo.levelAuthorName + ")";
+                if (Directory.Exists(path))
+                {
+                    int pathNum = 1;
+                    while (Directory.Exists(path + $" ({pathNum})")) ++pathNum;
+                    path += $" ({pathNum})";
+                }
+                await Task.Run(() => archive.ExtractToDirectory(path)).ConfigureAwait(false);
                 archive.Dispose();
+                songInfo.path = path;
             }
             catch (Exception e)
             {
@@ -162,8 +169,40 @@ namespace SongBrowser
             }
             zipStream.Close();
 
-            songInfo.path = Directory.GetDirectories(customSongsPath).FirstOrDefault();
-
+            //Correct subfolder
+            /*
+            try
+            {
+                string path = Directory.GetDirectories(customSongsPath).FirstOrDefault();
+                SongCore.Utilities.Utils.GrantAccess(path);
+                DirectoryInfo subfolder = new DirectoryInfo(path).GetDirectories().FirstOrDefault();
+                if(subfolder != null)
+                {
+                    Console.WriteLine(path);
+                    Console.WriteLine(subfolder.FullName);
+                    string newPath = CustomLevelPathHelper.customLevelsDirectoryPath + "/" + songInfo.id + " " + subfolder.Name;
+                    if (Directory.Exists(newPath))
+                    {
+                        int pathNum = 1;
+                        while (Directory.Exists(newPath + $" ({pathNum})")) ++pathNum;
+                        newPath = newPath + $" ({pathNum})";
+                    }
+                    Console.WriteLine(newPath);
+                    Directory.Move(subfolder.FullName, newPath);
+                    if (SongCore.Utilities.Utils.IsDirectoryEmpty(path))
+                    {
+                        Directory.Delete(path);
+                    }
+                    songInfo.path = newPath;
+                }
+                else
+                    Console.WriteLine("subfoldern null");
+            }
+            catch(Exception ex)
+            {
+                Logger.Error($"Unable to prepare Extracted Zip! \n {ex}");
+            }
+            */
             if (string.IsNullOrEmpty(songInfo.path))
             {
                 songInfo.path = customSongsPath;
@@ -178,18 +217,18 @@ namespace SongBrowser
                 try
                 {
 
-                    string dirName = new DirectoryInfo(customSongsPath).Name;
+                    //          string dirName = new DirectoryInfo(customSongsPath).Name;
 
-                    SongCore.Loader.SongsLoadedEvent -= Plugin.Instace.SongCore_SongsLoadedEvent;
+                    SongCore.Loader.SongsLoadedEvent -= Plugin.Instance.SongCore_SongsLoadedEvent;
                     Action<SongCore.Loader, Dictionary<string, CustomPreviewBeatmapLevel>> songsLoadedAction = null;
                     songsLoadedAction = (arg1, arg2) =>
                     {
                         SongCore.Loader.SongsLoadedEvent -= songsLoadedAction;
-                        SongCore.Loader.SongsLoadedEvent += Plugin.Instace.SongCore_SongsLoadedEvent;
+                        SongCore.Loader.SongsLoadedEvent += Plugin.Instance.SongCore_SongsLoadedEvent;
                     };
                     SongCore.Loader.SongsLoadedEvent += songsLoadedAction;
 
-                    SongCore.Loader.Instance.RefreshSongs();
+                    SongCore.Loader.Instance.RefreshSongs(false);
 
                 }
                 catch (Exception e)
@@ -321,6 +360,8 @@ namespace SongBrowser
 
                 Logger.Info($"{_alreadyDownloadedSongs.RemoveAll(x => x.Compare(song))} song removed");
             }).ConfigureAwait(false);
+
+
         }
 
 
@@ -330,14 +371,14 @@ namespace SongBrowser
             {
                 return _alreadyDownloadedSongs.Any(x => x.Compare(song));
             }
-
-            return false;
+            else
+                return false;
         }
 
         public static string GetLevelID(Song song)
         {
             Console.WriteLine("LevelID for: " + song.path);
-            string[] values = new string[] { song.hash, song.songName, song.songSubName, song.authorName, song.beatsPerMinute };
+            string[] values = new string[] { song.hash, song.songName, song.songSubName, song.levelAuthorName, song.bpm.ToString() };
             return string.Join("∎", values) + "∎";
         }
 
@@ -376,7 +417,7 @@ namespace SongBrowser
 
         public IEnumerator RequestSongByLevelIDCoroutine(string levelId, Action<Song> callback)
         {
-            UnityWebRequest wwwId = UnityWebRequest.Get($"{PluginConfig.beatsaverURL}/api/songs/search/hash/" + levelId);
+            UnityWebRequest wwwId = UnityWebRequest.Get($"{PluginConfig.beatsaverURL}/api/maps/by-hash/" + levelId);
             wwwId.timeout = 10;
 
             yield return wwwId.SendWebRequest();
@@ -388,16 +429,15 @@ namespace SongBrowser
             }
             else
             {
-                JSONNode node = JSON.Parse(wwwId.downloadHandler.text);
-
-                if (node["songs"].Count == 0)
+                JObject jNode = JObject.Parse(wwwId.downloadHandler.text);
+                if (jNode.Children().Count() == 0)
                 {
                     Logger.Error($"Song {levelId} doesn't exist on BeatSaver!");
                     callback?.Invoke(null);
                     yield break;
                 }
 
-                Song _tempSong = Song.FromSearchNode(node["songs"][0]);
+                Song _tempSong = Song.FromSearchNode((JObject)jNode);
                 callback?.Invoke(_tempSong);
             }
         }
@@ -409,7 +449,7 @@ namespace SongBrowser
 
         public IEnumerator RequestSongByKeyCoroutine(string key, Action<Song> callback)
         {
-            UnityWebRequest wwwId = UnityWebRequest.Get($"{PluginConfig.beatsaverURL}/api/songs/detail/" + key);
+            UnityWebRequest wwwId = UnityWebRequest.Get($"{PluginConfig.beatsaverURL}/api/maps/detail/" + key);
             wwwId.timeout = 10;
 
             yield return wwwId.SendWebRequest();
@@ -421,9 +461,9 @@ namespace SongBrowser
             }
             else
             {
-                JSONNode node = JSON.Parse(wwwId.downloadHandler.text);
+                JObject node = JObject.Parse(wwwId.downloadHandler.text);
 
-                Song _tempSong = new Song(node["song"]);
+                Song _tempSong = new Song((JObject)node, false);
                 callback?.Invoke(_tempSong);
             }
         }

+ 3 - 3
SongBrowserPlugin/DataAccess/Playlist.cs

@@ -223,7 +223,7 @@ namespace SongBrowser.DataAccess
                 if (song != null)
                     key = song.Key;
                 else
-                    yield return SongDownloader.Instance.RequestSongByLevelIDCoroutine(hash, (Song bsSong) => { if (bsSong != null) key = bsSong.id; });
+                    yield return SongDownloader.Instance.RequestSongByLevelIDCoroutine(hash, (Song bsSong) => { if (bsSong != null) key = bsSong._id; });
             }
             else if (!string.IsNullOrEmpty(levelId))
             {
@@ -231,7 +231,7 @@ namespace SongBrowser.DataAccess
                 if (song != null)
                     key = song.Key;
                 else
-                    yield return SongDownloader.Instance.RequestSongByLevelIDCoroutine(levelId.Substring(0, Math.Min(32, levelId.Length)), (Song bsSong) => { if (bsSong != null) key = bsSong.id; });
+                    yield return SongDownloader.Instance.RequestSongByLevelIDCoroutine(levelId.Substring(0, Math.Min(32, levelId.Length)), (Song bsSong) => { if (bsSong != null) key = bsSong._id; });
             }
             else if (level != null)
             {
@@ -239,7 +239,7 @@ namespace SongBrowser.DataAccess
                 if (song != null)
                     key = song.Key;
                 else
-                    yield return SongDownloader.Instance.RequestSongByLevelIDCoroutine(level.levelID.Substring(0, Math.Min(32, level.levelID.Length)), (Song bsSong) => { if (bsSong != null) key = bsSong.id; });
+                    yield return SongDownloader.Instance.RequestSongByLevelIDCoroutine(level.levelID.Substring(0, Math.Min(32, level.levelID.Length)), (Song bsSong) => { if (bsSong != null) key = bsSong._id; });
             }
         }
     }

+ 1 - 2
SongBrowserPlugin/Internals/BSEvents.cs

@@ -176,7 +176,7 @@ namespace SongBrowser.Internals
                     case LevelCompletionResults.LevelEndStateType.Failed:
                         InvokeAll(levelFailed, data, results);
                         break;
-                }
+                };
                 switch (results.levelEndAction)
                 {
                     case LevelCompletionResults.LevelEndAction.Quit:
@@ -186,7 +186,6 @@ namespace SongBrowser.Internals
                         InvokeAll(levelRestarted, data, results);
                         break;
                 }
-
             };
 
             InvokeAll(gameSceneLoaded);

+ 2 - 2
SongBrowserPlugin/Plugin.cs

@@ -13,7 +13,7 @@ namespace SongBrowser
     public class Plugin : IPlugin
     {
         public const string VERSION_NUMBER = "5.0.0";
-        public static Plugin Instace;
+        public static Plugin Instance;
 
         public string Name
         {
@@ -27,7 +27,7 @@ namespace SongBrowser
 
         public void OnApplicationStart()
         {
-            Instace = this;
+            Instance = this;
 
             SceneManager.sceneLoaded += SceneManager_sceneLoaded;
             SceneManager.activeSceneChanged += SceneManager_activeSceneChanged;

+ 1 - 0
SongBrowserPlugin/PluginConfig.cs

@@ -18,6 +18,7 @@ namespace SongBrowser
     {
         public static int maxSimultaneousDownloads = 3;
         public static string beatsaverURL = "https://beatsaver.com";
+        public static string scoresaberURL = "https://scoresaber.com";
         public static String CUSTOM_SONG_LEVEL_PACK_ID = "custom_levelpack_CustomLevels";
 
         public static bool beatDropInstalled = false;

+ 0 - 1
SongBrowserPlugin/SongBrowser.csproj

@@ -131,7 +131,6 @@
     <Compile Include="Internals\SimpleJSON.cs" />
     <Compile Include="Logging\Logger.cs" />
     <Compile Include="PluginConfig.cs" />
-    <Compile Include="UI\SceneEvents.cs" />
     <Compile Include="UI\BackButtonNavigationController.cs" />
     <Compile Include="UI\DownloadQueue\DownloadQueueTableCell.cs" />
     <Compile Include="UI\DownloadQueue\DownloadQueueViewController.cs" />

+ 3 - 1
SongBrowserPlugin/SongBrowserApplication.cs

@@ -61,7 +61,8 @@ namespace SongBrowser
 
             InstallHandlers();
 
-            StartCoroutine(ScrappedData.Instance.DownloadScrappedData((List<ScrappedSong> songs) => { }));
+            // Initialize Downloader Scrapped Data
+            StartCoroutine(ScrappedData.Instance.DownloadScrappedData((List<ScrappedSong> songs) => { }));            
 
             if (SongCore.Loader.AreSongsLoaded)
             {
@@ -72,6 +73,7 @@ namespace SongBrowser
                 SongCore.Loader.SongsLoadedEvent += OnSongLoaderLoadedSongs;
             }
 
+            // Useful to dump game objects.
             /*foreach (RectTransform rect in Resources.FindObjectsOfTypeAll<RectTransform>())
             {
                 Logger.Debug("RectTransform: {0}", rect.name);

+ 2 - 2
SongBrowserPlugin/UI/Browser/SongBrowserUI.cs

@@ -285,12 +285,12 @@ namespace SongBrowser.UI
 
                 string[] sortButtonNames = new string[]
                 {
-                    "Song", "Author", "Newest", "Plays", "PP", "Difficult", "Random"
+                    "Song", "Author", "Newest", "Upvotes", "Plays", "PP", "Difficult", "Random"
                 };
 
                 SongSortMode[] sortModes = new SongSortMode[]
                 {
-                    SongSortMode.Default, SongSortMode.Author, SongSortMode.Newest, SongSortMode.PlayCount, SongSortMode.PP, SongSortMode.Difficulty, SongSortMode.Random
+                    SongSortMode.Default, SongSortMode.Author, SongSortMode.Newest, SongSortMode.UpVotes, SongSortMode.PlayCount, SongSortMode.PP, SongSortMode.Difficulty, SongSortMode.Random
                 };
                 
                 _sortButtonGroup = new List<SongSortButton>();

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

@@ -41,8 +41,8 @@ namespace SongBrowser.UI.DownloadQueue
             }
 
             _songNameText.text = string.Format("{0}\n<size=80%>{1}</size>", song.songName, song.songSubName);
-            _authorText.text = song.authorName;
-            StartCoroutine(LoadScripts.LoadSpriteCoroutine(song.coverUrl, (cover) => { if (cover != null) _coverRawImage.texture = cover.texture ; }));
+            _authorText.text = song.levelAuthorName;
+            StartCoroutine(LoadScripts.LoadSpriteCoroutine(song.coverURL, (cover) => { if (cover != null) _coverRawImage.texture = cover.texture ; }));
 
             _bgImage.enabled = true;
             _bgImage.sprite = Sprite.Create((new Texture2D(1, 1)), new Rect(0, 0, 1, 1), Vector2.one / 2f);

+ 10 - 11
SongBrowserPlugin/UI/Playlists/PlaylistFlowCoordinator.cs

@@ -1,5 +1,5 @@
 using CustomUI.BeatSaber;
-using SimpleJSON;
+using Newtonsoft.Json.Linq;
 using SongBrowser.DataAccess;
 using SongBrowser.DataAccess.BeatSaverApi;
 using SongBrowser.Internals;
@@ -143,10 +143,10 @@ namespace SongBrowser.UI
                     beatSaverSong = new Song()
                     {
                         songName = item.songName,
-                        id = item.key,
+                        _id = item.key,
                         downloadingProgress = 0f,
                         hash = (item.levelId == null ? "" : item.levelId),
-                        downloadUrl = archiveUrl
+                        downloadURL = archiveUrl
                     };
                 }
 
@@ -164,7 +164,7 @@ namespace SongBrowser.UI
             bool _usingHash = false;
             if (!string.IsNullOrEmpty(song.key))
             {
-                url = $"{PluginConfig.beatsaverURL}/api/songs/detail/{song.key}";
+                url = $"{PluginConfig.beatsaverURL}/api/maps/detail/{song.key}";
                 if (!string.IsNullOrEmpty(playlist.customDetailUrl))
                 {
                     url = playlist.customDetailUrl + song.key;
@@ -172,13 +172,13 @@ namespace SongBrowser.UI
             }
             else if (!string.IsNullOrEmpty(song.hash))
             {
-                url = $"{PluginConfig.beatsaverURL}/api/songs/search/hash/{song.hash}";
+                url = $"{PluginConfig.beatsaverURL}/api/maps/by-hash/{song.hash}";
                 _usingHash = true;
             }
             else if (!string.IsNullOrEmpty(song.levelId))
             {
                 string hash = CustomHelpers.CheckHex(song.levelId.Substring(0, Math.Min(32, song.levelId.Length)));
-                url = $"{PluginConfig.beatsaverURL}/api/songs/search/hash/{hash}";
+                url = $"{PluginConfig.beatsaverURL}/api/maps/by-hash/{hash}";
                 _usingHash = true;
             }
             else
@@ -198,21 +198,20 @@ namespace SongBrowser.UI
             {
                 try
                 {
-                    JSONNode node = JSON.Parse(www.downloadHandler.text);
-
+                    JObject jNode = JObject.Parse(www.downloadHandler.text);
                     if (_usingHash)
                     {
-                        if (node["songs"].Count == 0)
+                        if (jNode["songs"].Count() == 0)
                         {
                             Logger.Error($"Song {song.songName} doesn't exist on BeatSaver!");
                             songCallback?.Invoke(null);
                             yield break;
                         }
-                        songCallback?.Invoke(Song.FromSearchNode(node["songs"][0]));
+                        songCallback?.Invoke(Song.FromSearchNode(jNode));
                     }
                     else
                     {
-                        songCallback?.Invoke(new Song(node["song"]));
+                        songCallback?.Invoke(new Song((JObject)jNode, false));
                     }
                 }
                 catch (Exception e)

+ 0 - 96
SongBrowserPlugin/UI/SceneEvents.cs

@@ -1,96 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using UnityEngine;
-using UnityEngine.SceneManagement;
-
-namespace SongBrowser
-{
-    public class SceneEvents : MonoBehaviour
-    {
-        public static SceneEvents Instance { get; private set; }
-
-        private bool _wasEnabled;
-
-        private GameScenesManager _gameScenesManager;
-        private MenuSceneSetup _menuSceneSetup;
-
-        public event Action<Scene> SceneTransitioned;
-        public event Action MenuSceneEnabled;
-        public event Action MenuSceneDisabled;
-
-        private void Awake()
-        {
-            Instance = this;
-            SceneManager.activeSceneChanged += SceneManagerOnActiveSceneChanged;
-            DontDestroyOnLoad(gameObject);
-        }
-
-        private void OnDestroy()
-        {
-            SceneManager.activeSceneChanged -= SceneManagerOnActiveSceneChanged;
-        }
-
-        private void SceneManagerOnActiveSceneChanged(Scene oldScene, Scene newScene)
-        {
-            if (_gameScenesManager == null)
-            {
-                _gameScenesManager = Resources.FindObjectsOfTypeAll<GameScenesManager>().FirstOrDefault();
-
-                if (_gameScenesManager == null) return;
-
-                _gameScenesManager.transitionDidFinishEvent += GameScenesManagerOnTransitionDidFinishEvent;
-                GameScenesManagerOnTransitionDidFinishEvent();
-            }
-        }
-
-        private void GameScenesManagerOnTransitionDidFinishEvent()
-        {
-            if (SceneTransitioned != null)
-            {
-                SceneTransitioned(SceneManager.GetActiveScene());
-            }
-
-            if (_menuSceneSetup == null)
-            {
-                _menuSceneSetup = Resources.FindObjectsOfTypeAll<MenuSceneSetup>().FirstOrDefault();
-                if (_menuSceneSetup == null)
-                {
-                    MenuDisabled();
-                    return;
-                }
-            }
-
-            if (!_menuSceneSetup.gameObject.activeInHierarchy)
-            {
-                MenuDisabled();
-            }
-            else
-            {
-                MenuEnabled();
-            }
-        }
-
-        private void MenuEnabled()
-        {
-            if (_wasEnabled) return;
-            _wasEnabled = true;
-            if (MenuSceneEnabled != null)
-            {
-                MenuSceneEnabled();
-            }
-        }
-
-        private void MenuDisabled()
-        {
-            if (!_wasEnabled) return;
-            _wasEnabled = false;
-            if (MenuSceneDisabled != null)
-            {
-                MenuSceneDisabled();
-            }
-        }
-    }
-}