//////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /// <summary> /// Download a song /// </summary> /// <param name="p_Song">Beat map</param> /// <param name="p_Token">Cancellation token</param> /// <param name="p_Progress">Progress reporter</param> /// <param name="p_Direct">Skip download counter ?</param> /// <returns></returns> public static async Task <bool> DownloadSong(Beatmap p_Song, CancellationToken p_Token, IProgress <double> p_Progress = null, bool p_Direct = false) { /* * Code from https://github.com/Kylemc1413/BeatSaverDownloader * * MIT License * * Copyright (c) 2019 andruzzzhka * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ p_Token.ThrowIfCancellationRequested(); try { string l_CustomSongsPath = CustomLevelPathHelper.customLevelsDirectoryPath; if (!Directory.Exists(l_CustomSongsPath)) { Directory.CreateDirectory(l_CustomSongsPath); } var l_ZIPBytes = await p_Song.DownloadZip(p_Direct, p_Token, p_Progress).ConfigureAwait(false); Logger.Instance?.Info("[SDK.Game][BeatSaver] Downloaded zip!"); return(await ExtractZipAsync(p_Token, p_Song, l_ZIPBytes, l_CustomSongsPath).ConfigureAwait(false)); } catch (Exception p_Exception) { if (p_Exception is TaskCanceledException) { Logger.Instance?.Warn("[SDK.Game][BeatSaver] Song Download Aborted."); throw p_Exception; } else { Logger.Instance?.Critical("[SDK.Game][BeatSaver] Failed to download Song!"); } } return(false); }
/// <summary> /// Download a song /// </summary> /// <param name="p_Song">Beat map</param> /// <param name="p_Token">Cancellation token</param> /// <param name="p_Progress">Progress reporter</param> /// <param name="p_Direct">Skip download counter ?</param> /// <returns></returns> public static async Task <bool> DownloadSong(Beatmap p_Song, CancellationToken p_Token, IProgress <double> p_Progress = null, bool p_Direct = false) { try { string l_CustomSongsPath = CustomLevelPathHelper.customLevelsDirectoryPath; if (!Directory.Exists(l_CustomSongsPath)) { Directory.CreateDirectory(l_CustomSongsPath); } var l_ZIPBytes = await p_Song.DownloadZip(p_Direct, p_Token, p_Progress).ConfigureAwait(false); Logger.Instance?.Info("Downloaded zip!"); return(await ExtractZipAsync(p_Song, l_ZIPBytes, l_CustomSongsPath).ConfigureAwait(false)); } catch (Exception p_Exception) { if (p_Exception is TaskCanceledException) { Logger.Instance?.Warn("Song Download Aborted."); } else { Logger.Instance?.Critical("Failed to download Song!"); } } return(false); }
private static async Task <byte[]> DownloadMap(Beatmap mapData) { try { byte[] zipData = await mapData.DownloadZip(); return(zipData); } catch (Exception ex) { MessageBox.Show("Unable to download map zip: " + ex.ToString()); return(null); } }
private async Task DownloadAndExtractBeatMap(Beatmap beatMap, string bsFolderPath, int songNumber, int totalSongs) { var zipBytes = await beatMap.DownloadZip(); var zipPath = Path.Combine($@"{bsFolderPath}\Beat Saber_Data\CustomLevels", $"{beatMap.Name}.zip"); using (var memStream = new MemoryStream(zipBytes)) { using (var writer = File.OpenWrite(zipPath)) { WriteToLog($"{songNumber + 1}/{totalSongs} | downloading {beatMap.Name}"); await memStream.CopyToAsync(writer).ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); } } using (var beatMapZip = ZipFile.OpenRead(zipPath)) { var beatMapFolderPath = Path.Combine($@"{bsFolderPath}\Beat Saber_Data\CustomLevels", $"{beatMap.Key} {beatMap.Name} - {beatMap.Uploader.Username}"); Directory.CreateDirectory(beatMapFolderPath); WriteToLog($"{songNumber + 1}/{totalSongs} | unzipping {beatMap.Name}"); foreach (var entry in beatMapZip.Entries) { using (var zipEntryStream = entry.Open()) using (var writer = File.OpenWrite(Path.Combine(beatMapFolderPath, entry.Name))) { await zipEntryStream.CopyToAsync(writer).ConfigureAwait(false); await writer.FlushAsync().ConfigureAwait(false); } } } WriteToLog($"{songNumber + 1}/{totalSongs} | success downloading {beatMap.Name}"); File.Delete(zipPath); }
private static async Task <IPreviewBeatmapLevel?> DownloadSong(string hash, IProgress <double>?progress, CancellationToken cancellationToken) { Beatmap bm = await Plugin.BeatSaver.Hash(hash, cancellationToken); if (bm == null) { Plugin.Log?.Warn($"Could not find song '{hash}' on Beat Saver."); return(null); } byte[] beatmapBytes = await bm.DownloadZip(false, cancellationToken, progress); string folderPath = Utils.GetSongDirectoryName(bm.Key, bm.Metadata.SongName, bm.Metadata.SongAuthorName); folderPath = Path.Combine(CustomLevelsFolder, folderPath); using (var ms = new MemoryStream(beatmapBytes)) { var result = await ZipUtils.ExtractZip(ms, folderPath); if (folderPath != result.OutputDirectory) { folderPath = result.OutputDirectory ?? throw new Exception("Zip extract failed, no output directory."); } if (result.Exception != null) { throw result.Exception; } } Plugin.Log.Info($"Downloaded song to '{folderPath}'"); using (var awaiter = new EventAwaiter <SongCore.Loader, ConcurrentDictionary <string, CustomPreviewBeatmapLevel> >(cancellationToken)) { try { SongCore.Loader.SongsLoadedEvent += awaiter.OnEvent; SongCore.Collections.AddSong($"custom_level_{hash}", folderPath); SongCore.Loader.Instance.RefreshSongs(false); await awaiter.Task; } catch (OperationCanceledException) { return(null); } catch (Exception e) { Plugin.Log?.Error($"Error waiting for songs to load: {e.Message}"); Plugin.Log?.Debug(e); throw; } finally { SongCore.Loader.SongsLoadedEvent -= awaiter.OnEvent; } } CustomPreviewBeatmapLevel?beatmap = SongCore.Loader.GetLevelByHash(hash); if (beatmap == null) { Plugin.Log?.Warn($"Couldn't get downloaded beatmap '{bm.Metadata.SongName ?? hash}' from SongCore, this shouldn't happen."); } return(beatmap); }