From 7c3bd4109ec62b90b9ede553591b464abca32efd Mon Sep 17 00:00:00 2001 From: pleb Date: Sat, 18 Apr 2026 15:58:22 -0700 Subject: [PATCH] Load user's playlists and print confirmation --- Setlist/Plugin.cs | 38 ++++++++++++++- Setlist/Setlist.csproj | 8 +++- Setlist/manifest.json | 3 +- docs/playlistmanager-add-map.md | 82 +++++++++++++++++++++++++++++++++ 4 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 docs/playlistmanager-add-map.md diff --git a/Setlist/Plugin.cs b/Setlist/Plugin.cs index 2879303..5672aa7 100644 --- a/Setlist/Plugin.cs +++ b/Setlist/Plugin.cs @@ -1,3 +1,4 @@ +using System; using IPA; using IPALogger = IPA.Logging.Logger; @@ -23,7 +24,42 @@ namespace Setlist [OnStart] public void OnApplicationStart() { - Log.Info("Hello World"); + try + { + var playlists = BeatSaberPlaylistsLib.PlaylistManager.DefaultManager.GetAllPlaylists( + includeChildren: true, + out AggregateException loadErrors); + + if (loadErrors != null) + { + Log.Error(loadErrors.Message); + foreach (var inner in loadErrors.InnerExceptions) + { + Log.Error(inner.ToString()); + } + } + + if (playlists == null || playlists.Length == 0) + { + Log.Info("No playlists loaded (or playlist library not initialized yet)."); + return; + } + + foreach (var playlist in playlists) + { + var hasSyncUrl = false; + if (playlist.TryGetCustomData("syncURL", out var syncObj) && syncObj is string url) + { + hasSyncUrl = !string.IsNullOrWhiteSpace(url); + } + + Log.Info($"Playlist \"{playlist.Title}\": hasSyncUrl={hasSyncUrl}"); + } + } + catch (Exception ex) + { + Log.Error(ex.ToString()); + } } [OnExit] diff --git a/Setlist/Setlist.csproj b/Setlist/Setlist.csproj index d1bb5e8..cea99ef 100644 --- a/Setlist/Setlist.csproj +++ b/Setlist/Setlist.csproj @@ -10,7 +10,7 @@ Properties Setlist Setlist - v4.7.2 + v4.8 512 true portable @@ -89,6 +89,10 @@ $(BeatSaberDir)\Beat Saber_Data\Managed\UnityEngine.VRModule.dll False + + $(BeatSaberDir)\Libs\BeatSaberPlaylistsLib.dll + False + @@ -107,7 +111,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + 1.0.3 all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/Setlist/manifest.json b/Setlist/manifest.json index 131ad9d..283c064 100644 --- a/Setlist/manifest.json +++ b/Setlist/manifest.json @@ -7,6 +7,7 @@ "description": "Syncs playlists with external sources.", "gameVersion": "1.40.8", "dependsOn": { - "BSIPA": "^4.3.0" + "BSIPA": "^4.3.0", + "BeatSaberPlaylistsLib": "^1.7.0" } } diff --git a/docs/playlistmanager-add-map.md b/docs/playlistmanager-add-map.md new file mode 100644 index 0000000..bd9fdf6 --- /dev/null +++ b/docs/playlistmanager-add-map.md @@ -0,0 +1,82 @@ +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()`. \ No newline at end of file