////////////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// Create a fake CustomBeatmapLevel from BeatSaver BeatMap
        /// </summary>
        /// <param name="p_BeatMap">BeatMap instance</param>
        /// <returns></returns>
        public static CustomBeatmapLevel CreateFakeCustomBeatmapLevelFromBeatMap(BeatSaverSharp.Beatmap p_BeatMap)
        {
            if (p_BeatMap == null)
            {
                return(null);
            }

            return(Internal.BeatSaver_CustomBeatmapLevel.FromBeatSaver(p_BeatMap));
        }
        private async Task ExtractZipAsync(BeatSaverSharp.Beatmap songInfo, byte[] zip, string customSongsPath, bool overwrite = false)
        {
            Stream zipStream = new MemoryStream(zip);

            try
            {
                ZipArchive archive  = new ZipArchive(zipStream, ZipArchiveMode.Read);
                string     basePath = songInfo.Key + " (" + songInfo.Metadata.SongName + " - " + songInfo.Metadata.LevelAuthorName + ")";
                basePath = string.Join("", basePath.Split((Path.GetInvalidFileNameChars().Concat(Path.GetInvalidPathChars()).ToArray())));
                string path = customSongsPath + "/" + basePath;
                if (!overwrite && Directory.Exists(path))
                {
                    int pathNum = 1;
                    while (Directory.Exists(path + $" ({pathNum})"))
                    {
                        ++pathNum;
                    }
                    path += $" ({pathNum})";
                }
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                await Task.Run(() =>
                {
                    foreach (var entry in archive.Entries)
                    {
                        var entryPath = Path.Combine(path, entry.Name); // Name instead of FullName for better security and because song zips don't have nested directories anyway
                        if (overwrite || !File.Exists(entryPath))       // Either we're overwriting or there's no existing file
                        {
                            entry.ExtractToFile(entryPath, overwrite);
                        }
                    }
                }).ConfigureAwait(false);

                archive.Dispose();
            }
            catch (Exception e)
            {
                Plugin.Log.Critical($"Unable to extract ZIP! Exception: {e}");
                return;
            }
            zipStream.Close();
        }