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);
                    }
                }
            }
        }
예제 #2
0
        //we will see if this cache is enough of a performance boost to warrant the extra hassle of keeping it up to date
        public MusicConfigCache(MainLevelPackCollectionObject mainPack)
        {
            Log.LogMsg("Building cache...");
            Stopwatch sw = new Stopwatch();

            try
            {
                sw.Start();
                PlaylistCache.Clear();
                SongCache.Clear();
                int plCtr = 0;
                foreach (var x in mainPack.BeatmapLevelPacks)
                {
                    if (PlaylistCache.ContainsKey(x.Object.PackID))
                    {
                        Log.LogErr($"Cache building: playlist ID {x.Object.PackID} exists multiple times in the main level list!  Skipping redundant copies...");
                    }
                    else
                    {
                        var pns = new PlaylistAndSongs()
                        {
                            Playlist = x.Object, Order = plCtr
                        };
                        int ctr = 0;
                        foreach (var y in x.Object.BeatmapLevelCollection.Object.BeatmapLevels)
                        {
                            if (pns.Songs.ContainsKey(y.Object.LevelID))
                            {
                                Log.LogErr($"Cache building: song ID {y.Object.LevelID} exists multiple times in playlist {x.Object.PackID}!");
                            }
                            else
                            {
                                pns.Songs.Add(y.Object.LevelID, new OrderedSong()
                                {
                                    Song = y.Object, Order = ctr
                                });
                            }
                            if (SongCache.ContainsKey(y.Object.LevelID))
                            {
                                Log.LogErr($"Cache building: cannot add song ID {y.Object.LevelID} in playlist ID {x.Object.PackID} because it already exists in {SongCache[y.Object.LevelID].Playlist.PackID}!");
                            }
                            else
                            {
                                SongCache.Add(y.Object.LevelID, new SongAndPlaylist()
                                {
                                    Song = y.Object, Playlist = x.Object
                                });
                            }
                            ctr++;
                        }
                        PlaylistCache.Add(x.Object.PackID, pns);
                        plCtr++;
                    }
                }
                sw.Stop();
                Log.LogMsg($"Building cache took {sw.ElapsedMilliseconds}ms");
            }
            catch (Exception ex)
            {
                Log.LogErr("Exception building cache!", ex);
                throw;
            }
        }