public async Task BeatmapDownloadByHash(string hash, CancellationToken token, IProgress <double> progress = null, bool direct = false)
        {
            var options = new StandardRequestOptions {
                Token = token, Progress = progress
            };
            bool songDownloaded = false;

            while (!songDownloaded)
            {
                try
                {
                    var song = await beatSaverInstance.Hash(hash, options);
                    await BeatSaverBeatmapDownload(song, options, direct);

                    songDownloaded = true;
                }
                catch (Exception e)
                {
                    if (e is BeatSaverSharp.Exceptions.RateLimitExceededException rateLimitException)
                    {
                        double timeRemaining = (rateLimitException.RateLimit.Reset - DateTime.Now).TotalMilliseconds;
                        timeRemaining = timeRemaining > 0 ? timeRemaining : 0;
                        await Task.Delay((int)timeRemaining);

                        continue;
                    }
                    else if (!(e is TaskCanceledException))
                    {
                        Plugin.Log.Critical(string.Format("Failed to download Song {0}. Exception: {1}", hash, e.ToString()));
                    }
                    songDownloaded = true;
                }
            }
        }
        public async Task BeatmapDownloadByHash(string hash, CancellationToken token, IProgress <double> progress = null, bool direct = false)
        {
            var options = new StandardRequestOptions {
                Token = token, Progress = progress
            };
            var song = await beatSaverInstance.Hash(hash, options);

            try
            {
                string customSongsPath = CustomLevelPathHelper.customLevelsDirectoryPath;
                if (!Directory.Exists(customSongsPath))
                {
                    Directory.CreateDirectory(customSongsPath);
                }
                var zip = await song.ZipBytes(direct, options).ConfigureAwait(false);
                await ExtractZipAsync(song, zip, customSongsPath).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                if (e is TaskCanceledException)
                {
                    Plugin.Log.Warn("Song Download Aborted.");
                }
                else
                {
                    Plugin.Log.Critical("Failed to download Song!");
                }
            }
        }
        private async Task BeatSaverBeatmapDownload(Beatmap song, StandardRequestOptions options, bool direct)
        {
            string customSongsPath = CustomLevelPathHelper.customLevelsDirectoryPath;

            if (!Directory.Exists(customSongsPath))
            {
                Directory.CreateDirectory(customSongsPath);
            }
            var zip = await song.ZipBytes(direct, options).ConfigureAwait(false);

            await ExtractZipAsync(zip, customSongsPath, songInfo : song).ConfigureAwait(false);
        }
        public async Task BeatmapDownloadByHash(string hash, CancellationToken token, IProgress <double> progress = null, bool direct = false)
        {
            var options = new StandardRequestOptions {
                Token = token, Progress = progress
            };
            var song = await beatSaverInstance.Hash(hash, options);

            try
            {
                await BeatSaverBeatmapDownload(song, options, direct);
            }
            catch (Exception e)
            {
                if (!(e is TaskCanceledException))
                {
                    Plugin.Log.Critical(string.Format("Failed to download Song {0}", hash));
                }
            }
        }