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

118 lines
5.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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()`:
```64:70:PlaylistManager/UI/ViewControllers/LevelDetailButtonsViewController.cs
[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:
```97:103:PlaylistManager/UI/ViewControllers/AddPlaylistModalController.cs
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:
```165:204:PlaylistManager/UI/ViewControllers/AddPlaylistModalController.cs
[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:
```16:18:PlaylistManager/Utilities/Events.cs
/// <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:
```187:194:PlaylistManager/UI/ViewControllers/AddPlaylistModalController.cs
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.