using System; using System.Collections.Generic; using IPA; using IPALogger = IPA.Logging.Logger; namespace Setlist { [Plugin(RuntimeOptions.SingleStartInit)] public class Plugin { internal static Plugin Instance { get; private set; } /// /// BSIPA logger (shows in BSIPA console / game logs when verbose). /// internal static IPALogger Log { get; private set; } [Init] public Plugin(IPALogger logger) { Instance = this; Log = logger; } [OnStart] public void OnApplicationStart() { 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; } var entries = new List<(string Title, bool HasSyncUrl, string BeatLeaderGuid, string OwnerId)>(); foreach (var playlist in playlists) { var hasSyncUrl = false; string syncUrl = null; if (playlist.TryGetCustomData("syncURL", out var syncObj) && syncObj is string url) { syncUrl = url; hasSyncUrl = !string.IsNullOrWhiteSpace(url); } string ownerId = null; if (playlist.TryGetCustomData("owner", out var ownerObj) && ownerObj is string o) { ownerId = string.IsNullOrWhiteSpace(o) ? null : o.Trim(); } string blGuid = null; if (hasSyncUrl && BeatLeaderPlaylistOwnership.TryExtractBeatLeaderPlaylistGuid(syncUrl, out var g)) { blGuid = g; } entries.Add((playlist.Title, hasSyncUrl, blGuid, ownerId)); } BeatLeaderPlaylistOwnership.ScheduleVerifyAndLog(entries, Log); } catch (Exception ex) { Log.Error(ex.ToString()); } } [OnExit] public void OnApplicationQuit() { } /// /// One-line log for a playlist. Ownership is inferred only from playlist JSON customData /// (owner vs the game's platform user id). No network verification. /// internal static string FormatPlaylistLogLine( string title, bool hasSyncUrl, string beatLeaderPlaylistGuid, string ownerId, string platformUserId) { var ownerToken = string.IsNullOrEmpty(ownerId) ? "owner=n/a" : $"owner={ownerId}"; string ownerMatchesPlatformPart; if (!hasSyncUrl) { ownerMatchesPlatformPart = "ownerMatchesPlatform=n/a (no sync URL)"; } else if (string.IsNullOrEmpty(beatLeaderPlaylistGuid)) { ownerMatchesPlatformPart = "ownerMatchesPlatform=n/a (sync URL is not an api.beatleader.com /playlist/guid/… URL)"; } else if (string.IsNullOrEmpty(platformUserId)) { ownerMatchesPlatformPart = "ownerMatchesPlatform=unknown (platform user id not available yet; cannot compare to owner)"; } else if (string.IsNullOrEmpty(ownerId)) { ownerMatchesPlatformPart = "ownerMatchesPlatform=false (BeatLeader playlist URL but no owner field in playlist JSON)"; } else if (string.Equals(ownerId, platformUserId, StringComparison.Ordinal)) { ownerMatchesPlatformPart = "ownerMatchesPlatform=true (playlist owner field equals platform user id)"; } else { ownerMatchesPlatformPart = "ownerMatchesPlatform=false (playlist owner field differs from platform user id)"; } return $"Playlist \"{title}\": hasSyncUrl={hasSyncUrl}, {ownerToken}, {ownerMatchesPlatformPart}"; } } }