예제 #1
0
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(Playlist.PlaylistID))
            {
                throw new Exception("PlaylistID must be provided.");
            }

            if (string.IsNullOrEmpty(Playlist.PlaylistName))
            {
                throw new Exception($"PlaylistName must be provided for ID {Playlist.PlaylistName}");
            }

            var songsAssetFile = context.Engine.GetSongsAssetsFile();
            BeatmapLevelPackObject levelPack = null;

            if (context.Cache.PlaylistCache.ContainsKey(Playlist.PlaylistID))
            {
                Log.LogMsg($"Playlist {Playlist.PlaylistID} will be updated");
                levelPack                = context.Cache.PlaylistCache[Playlist.PlaylistID].Playlist;
                levelPack.PackName       = Playlist.PlaylistName;
                Playlist.LevelPackObject = levelPack;
                OpCommon.UpdateCoverImage(Playlist, context, songsAssetFile);
            }
            else
            {
                levelPack = OpCommon.CreatePlaylist(context, Playlist, songsAssetFile);
            }
        }
예제 #2
0
 internal override void PerformOp(OpContext context)
 {
     if (string.IsNullOrEmpty(SongID))
     {
         throw new InvalidOperationException("SongID must be provided.");
     }
     if (!context.Cache.SongCache.ContainsKey(SongID))
     {
         throw new InvalidOperationException("SongID does not exist.");
     }
     OpCommon.DeleteSong(context, SongID);
 }
예제 #3
0
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(PlaylistID))
            {
                throw new InvalidOperationException("Playlist ID must be provided.");
            }

            if (!context.Cache.PlaylistCache.ContainsKey(PlaylistID))
            {
                throw new InvalidOperationException("Playlist ID does not exist.");
            }

            if (PlaylistID == "CustomSongs")
            {
                throw new InvalidOperationException("Don't delete CustomSongs playlist, it's needed for things.");
            }

            OpCommon.DeletePlaylist(context, PlaylistID, DeleteSongsOnPlaylist);
        }
        internal override void PerformOp(OpContext context)
        {
            Comparer <SongAndPlaylist>     comparer;
            Func <SongAndPlaylist, string> nameGetter;

            switch (SortMode)
            {
            case PlaylistSortMode.Name:
                nameGetter = (s) =>
                {
                    if (s.Song.SongName?.Length < 1)
                    {
                        return("");
                    }
                    return(s.Song.SongName.Substring(0, 1).ToUpper());
                };
                comparer = Comparer <SongAndPlaylist> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.SongName.ToUpper().CompareTo(s2.Song.SongName.ToUpper()));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            case PlaylistSortMode.MaxDifficulty:
                nameGetter = (s) =>
                {
                    var max = s.Song?.DifficultyBeatmapSets?.SelectMany(x => x?.DifficultyBeatmaps)?.Max(x => x?.Difficulty);
                    if (max == null)
                    {
                        return(Difficulty.Easy.ToString());
                    }

                    return(max.ToString());
                };
                comparer = Comparer <SongAndPlaylist> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.DifficultyBeatmapSets.SelectMany(x => x.DifficultyBeatmaps).Max(x => x.Difficulty)
                               .CompareTo(s2.Song.DifficultyBeatmapSets.SelectMany(x => x.DifficultyBeatmaps).Max(x => x.Difficulty)));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            case PlaylistSortMode.LevelAuthor:
                nameGetter = (s) =>
                {
                    return(s.Song?.LevelAuthorName?.ToUpper() ?? "");
                };
                comparer = Comparer <SongAndPlaylist> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.LevelAuthorName.ToUpper().CompareTo(s2.Song.LevelAuthorName.ToUpper()));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            default:
                throw new NotImplementedException("Unhandled playlist sort mode.");
            }
            var songList = context.Cache.SongCache.Values.ToArray();

            Array.Sort(songList, comparer);
            var songsAssetFile = context.Engine.GetSongsAssetsFile();
            PlaylistAndSongs currentPlaylist = null;
            int    plCtr            = 0;
            string previousSongName = "";

            for (int i = 0; i < songList.Length; i++)
            {
                var song = songList[i];
                if (BSConst.KnownLevelIDs.Contains(song.Song.LevelID) || BSConst.KnownLevelPackIDs.Contains(song.Playlist.PackID))
                {
                    continue;
                }
                var curSongName = nameGetter(song);
                var packID      = $"Auto_{curSongName}";
                if (currentPlaylist == null || currentPlaylist.Playlist.PackID != packID)
                {
                    bool newPlaylist = true;
                    if (currentPlaylist != null && SortMode == PlaylistSortMode.Name)
                    {
                        if (plCtr < MaxPerNamePlaylist)
                        {
                            newPlaylist = false;
                        }
                        else
                        {
                            currentPlaylist.Playlist.PackName += " - " + previousSongName;
                        }
                    }
                    if (newPlaylist)
                    {
                        if (!context.Cache.PlaylistCache.ContainsKey(packID))
                        {
                            OpCommon.CreatePlaylist(context, new Models.BeatSaberPlaylist()
                            {
                                PlaylistID   = packID,
                                PlaylistName = curSongName
                            }, songsAssetFile);
                            currentPlaylist = context.Cache.PlaylistCache[packID];
                        }
                        else
                        {
                            currentPlaylist = context.Cache.PlaylistCache[packID];
                            currentPlaylist.Playlist.PackName = curSongName;
                        }

                        plCtr = 0;
                    }
                }

                //update assets
                var oldPl  = context.Cache.PlaylistCache[song.Playlist.PackID];
                var oldPtr = oldPl.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Where(x => x.Object.LevelID == song.Song.LevelID).First();
                oldPtr.Dispose();
                oldPl.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(oldPtr);
                currentPlaylist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(song.Song.PtrFrom(currentPlaylist.Playlist.BeatmapLevelCollection.Object));

                //update cache
                oldPl.Songs.Remove(song.Song.LevelID);
                song.Playlist = currentPlaylist.Playlist;
                currentPlaylist.Songs.Add(song.Song.LevelID, new OrderedSong()
                {
                    Song = song.Song, Order = plCtr
                });

                plCtr++;
                previousSongName = curSongName;
                if (SortMode == PlaylistSortMode.Name && i == songList.Length - 1)
                {
                    currentPlaylist.Playlist.PackName += " - " + curSongName;
                }
            }
            if (RemoveEmptyPlaylists)
            {
                foreach (var pl in context.Cache.PlaylistCache.ToList())
                {
                    //leave CustomSongs alone
                    if (pl.Value.Songs.Count < 1 && pl.Key != "CustomSongs")
                    {
                        OpCommon.DeletePlaylist(context, pl.Key, false);
                    }
                }
            }
        }
예제 #5
0
        public static void DeletePlaylist(OpContext context, string playlistID, bool deleteSongsOnPlaylist)
        {
            var playlist = context.Cache.PlaylistCache[playlistID];

            if (deleteSongsOnPlaylist)
            {
                try
                {
                    foreach (var song in playlist.Songs.ToList())
                    {
                        try
                        {
                            OpCommon.DeleteSong(context, song.Key);
                        }
                        catch (Exception ex)
                        {
                            Log.LogErr($"Exception trying to delete song id {song.Key} while deleting playlist id {playlist.Playlist.PackID}, will be unlinked in cache.  This may leave unused data in the assets.", ex);
                            try
                            {
                                context.Cache.SongCache.Remove(song.Value.Song.LevelID);
                                playlist.Songs.Remove(song.Value.Song.LevelID);
                            }
                            catch (Exception ex2)
                            {
                                Log.LogErr($"Exception cleaning up cache for song id {song.Key} in playlist if {playlist.Playlist.PackID} while recovering from a failed delete.", ex2);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    //really this shouldn't ever get hit anymore.  Probably can remove it.
                    Log.LogErr($"Deleting songs on playlist ID {playlist?.Playlist?.PackID} failed! Attempting to recover by removing links to songs, although this may leave extra stuff in assets!");
                    try
                    {
                        var bmCol = playlist?.Playlist?.BeatmapLevelCollection?.Object?.BeatmapLevels?.ToList();
                        if (bmCol != null)
                        {
                            bmCol.ForEach(x => { playlist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(x); x.Dispose(); });
                        }
                    }
                    catch (Exception ex2)
                    {
                        Log.LogErr($"Failed to recover by removing song pointers while deleting playlist {playlist?.Playlist?.PackID}!  This will definitely leave stuff in assets.", ex2);
                    }
                }
                playlist.Songs.Clear();
            }
            //this should be done in song delete already
            //playlist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.ForEach(x => { x.Target.ParentFile.DeleteObject(x.Object); x.Dispose(); });
            var mlp    = context.Engine.GetMainLevelPack();
            var aop    = context.Engine.GetAlwaysOwnedModel();
            var mlpptr = mlp.BeatmapLevelPacks.FirstOrDefault(x => x.Object.PackID == playlist.Playlist.PackID);
            var aopptr = aop.AlwaysOwnedPacks.FirstOrDefault(x => x.Object.PackID == playlist.Playlist.PackID);

            if (mlpptr != null)
            {
                mlp.BeatmapLevelPacks.Remove(mlpptr);
                mlpptr.Dispose();
            }
            else
            {
                Log.LogErr($"The playlist id {playlist.Playlist.PackID} didn't exist in the main level packs");
            }
            if (aopptr != null)
            {
                aop.AlwaysOwnedPacks.Remove(aopptr);
                aopptr.Dispose();
            }
            else
            {
                Log.LogErr($"The playlist id {playlist.Playlist.PackID} didn't exist in the always owned level packs");
            }
            //don't delete built in packs assets, just unlink them
            if (!BSConst.KnownLevelPackIDs.Contains(playlist.Playlist.PackID))
            {
                var plParent = playlist.Playlist.ObjectInfo.ParentFile;
                plParent.DeleteObject(playlist.Playlist.CoverImage.Object.RenderData.Texture.Object);
                playlist.Playlist.CoverImage.Object.RenderData.Texture.Dispose();
                plParent.DeleteObject(playlist.Playlist.CoverImage.Object);
                plParent.DeleteObject(playlist.Playlist);
                playlist.Playlist.CoverImage.Dispose();
            }
            context.Cache.PlaylistCache.Remove(playlistID);
        }
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(Song.SongID))
            {
                throw new InvalidOperationException("SongID must be set on the song!");
            }
            if (string.IsNullOrEmpty(Song.CustomSongPath))
            {
                throw new InvalidOperationException("CustomSongPath must be set on the song!");
            }
            if (!context.Cache.PlaylistCache.ContainsKey(PlaylistID))
            {
                throw new KeyNotFoundException($"PlaylistID {PlaylistID} not found in the cache!");
            }
            bool exists = context.Cache.SongCache.ContainsKey(Song.SongID);

            if (exists && !OverwriteIfExists)
            {
                throw new AddSongException(AddSongFailType.SongExists, $"SongID {Song.SongID} already exists!");
            }

            if (exists && OverwriteIfExists)
            {
                OpCommon.DeleteSong(context, Song.SongID);
            }

            if (context.Cache.SongCache.ContainsKey(Song.SongID))
            {
                throw new AddSongException(AddSongFailType.SongExists, $"SongID {Song.SongID} already exists, even though it should have been deleted to be replaced!");
            }

            BeatmapLevelDataObject level = null;

            try
            {
                var songsAssetFile       = context.Engine.GetSongsAssetsFile();
                CustomLevelLoader loader = new CustomLevelLoader(songsAssetFile, context.Config);
                var deser = loader.DeserializeFromJson(Song.CustomSongPath, Song.SongID);
                level = loader.LoadSongToAsset(deser, Song.CustomSongPath, true);
            }
            catch (Exception ex)
            {
                throw new Exception($"Exception loading custom song folder '{Song.CustomSongPath}' for SongID {Song.SongID}", ex);
            }

            if (level == null)
            {
                throw new AddSongException(AddSongFailType.InvalidFormat, $"Song at folder '{Song.CustomSongPath}' for SongID {Song.SongID} failed to load");
            }

            Song.LevelData       = level;
            Song.LevelAuthorName = level.LevelAuthorName;
            Song.SongAuthorName  = level.SongAuthorName;
            Song.SongName        = level.SongName;
            Song.SongSubName     = level.SongSubName;
            var playlist = context.Cache.PlaylistCache[PlaylistID];

            playlist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(Song.LevelData.PtrFrom(playlist.Playlist.BeatmapLevelCollection.Object));
            playlist.Songs.Add(Song.SongID, new OrderedSong()
            {
                Song = Song.LevelData, Order = playlist.Songs.Count
            });
            context.Cache.SongCache.Add(Song.SongID, new SongAndPlaylist()
            {
                Playlist = playlist.Playlist, Song = Song.LevelData
            });
            var qfos = context.Engine.QueuedFileOperations.Where(x => x.Tag == Song.SongID && x.Type == QueuedFileOperationType.DeleteFolder || x.Type == QueuedFileOperationType.DeleteFile).ToList();

            foreach (var q in qfos)
            {
                context.Engine.QueuedFileOperations.Remove(q);
            }
        }