setlist/docs/playlistmanager-add-map.md
2026-04-18 21:40:23 -07:00

5.4 KiB
Raw Permalink Blame History

For reference, the source code is in ~/src/rithik-b/PlaylistManager.

Here is how “add this map to a playlist” is wired in this repo.

1. User clicks Add (opens the picker)

The Add button on the level detail screen calls AddPlaylistModalController.ShowModal():

        [UIAction("add-button-click")]
        private void OpenAddModal()
        {
            addPlaylistController.ShowModal();
        }

ShowModal parses the BSML if needed, opens the modal, and lists playlists from the default lib manager:

        internal void ShowModal()
        {
            Parse();
            parserParams.EmitEvent("close-modal");
            parserParams.EmitEvent("open-modal");
            ShowPlaylistsForManager(PlaylistLibUtils.playlistManager);
        }

2. User picks a playlist row — that is where the map is actually added

The real work is in AddPlaylistModalController.OnCellSelect: after navigating folders, choosing a playlist calls IPlaylist.Add(...) from BeatSaberPlaylistsLib, then persists and notifies:

        [UIAction("select-cell")]
        private void OnCellSelect(TableView tableView, int index)
        {
            playlistTableData.TableView.ClearSelection();
            // Folder Selected
            if (index < childManagers.Count)
            {
                ShowPlaylistsForManager(childManagers[index]);
            }
            else
            {
                index -= childManagers.Count;
                var selectedPlaylist = childPlaylists[index];
                IPlaylistSong playlistSong;
                if (HighlightDifficulty)
                {
                    playlistSong = selectedPlaylist.Add(standardLevelDetailViewController.beatmapLevel, standardLevelDetailViewController.beatmapKey);
                }
                else
                {
                    playlistSong = selectedPlaylist.Add(standardLevelDetailViewController.beatmapLevel);
                }
                try
                {
                    selectedPlaylist.RaisePlaylistChanged();
                    parentManager.StorePlaylist(selectedPlaylist);
                    popupModalsController.ShowOkModal(modalTransform, string.Format("Song successfully added to {0}", selectedPlaylist.Title), null, animateParentCanvas: false);
                    // TODO: Doesn't refresh the sprite.
                    Events.RaisePlaylistSongAdded(playlistSong, selectedPlaylist);
                }
                catch (Exception e)
                {
                    popupModalsController.ShowOkModal(modalTransform, "An error occured while adding song to playlist.", null, animateParentCanvas: false);
                    Plugin.Log.Critical(string.Format("An exception was thrown while adding a song to a playlist.\nException Message: {0}", e.Message));
                }
                finally
                {
                    ShowPlaylistsForManager(parentManager);
                }
            }
        }

So:

  • PlaylistManager code: AddPlaylistModalController.OnCellSelect (orchestration, UI, StorePlaylist, Events.RaisePlaylistSongAdded).
  • Library code: selectedPlaylist.Add(...) — implementation of how the entry is stored lives in BeatSaberPlaylistsLib (IPlaylist), not in this repository.

There is no other .Add( on a playlist for this flow in the grep results; removing a song is the parallel path in LevelDetailButtonsViewController.RemoveSong().

hooking into the process

1. Subscribe to PlaylistManagers public event (simplest)

After a successful add from the Add to playlist UI, PlaylistManager raises a public static event:

        /// <summary>
        /// Raised when an <see cref="BeatSaberPlaylistsLib.Types.IPlaylistSong"/> is added to an <see cref="BeatSaberPlaylistsLib.Types.IPlaylist"/>
        /// </summary>
        public static event Action<BeatSaberPlaylistsLib.Types.IPlaylistSong, BeatSaberPlaylistsLib.Types.IPlaylist> playlistSongAdded;

It is invoked after RaisePlaylistChanged() and StorePlaylist() succeed:

                try
                {
                    selectedPlaylist.RaisePlaylistChanged();
                    parentManager.StorePlaylist(selectedPlaylist);
                    popupModalsController.ShowOkModal(modalTransform, string.Format("Song successfully added to {0}", selectedPlaylist.Title), null, animateParentCanvas: false);
                    // TODO: Doesn't refresh the sprite.
                    Events.RaisePlaylistSongAdded(playlistSong, selectedPlaylist);
                }

In your plugin: add a reference to PlaylistManager.dll, a manifest dependency on PlaylistManager, then subscribe in OnEnable (or menu init) and unsubscribe in OnDisable:

  • Namespace: PlaylistManager.Utilities
  • Type: Events
  • Event: playlistSongAdded
  • Handler signature: (IPlaylistSong song, IPlaylist playlist) from BeatSaberPlaylistsLib.Types

Caveat: This is only raised for adds that go through this code path. It is the only RaisePlaylistSongAdded call site in the repo, so adds done only via BeatSaberPlaylistsLib (or another mod) will not fire this event.