Update Setlist for Beat Saber 1.44.1 startup scan

This commit is contained in:
pleb
2026-07-19 20:25:22 -07:00
parent 14d21ad6a3
commit a3b8169fd6
7 changed files with 79 additions and 87 deletions
+24 -54
View File
@@ -3,8 +3,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using BeatSaberPlaylistsLib.Types;
using UnityEngine;
using IPALogger = IPA.Logging.Logger;
@@ -20,7 +18,6 @@ namespace Setlist
private const float PlatformUserPollStepSeconds = 0.5f;
/// <summary>How long to wait for <see cref="PlatformLeaderboardsModel"/> to appear and populate <c>playerId</c> (plugin runs before menu init).</summary>
private const float PlatformUserWaitTimeoutSeconds = 30f;
private const float PlatformUserGetUserInfoRetrySeconds = 3f;
internal static bool TryExtractBeatLeaderPlaylistGuid(string syncUrl, out string guid)
{
@@ -111,55 +108,18 @@ namespace Setlist
internal static IEnumerator FetchPlatformUserIdCoroutine(Action<string> onDone)
{
var waited = 0f;
var lastGetUserInfoAttempt = -PlatformUserGetUserInfoRetrySeconds;
while (waited < PlatformUserWaitTimeoutSeconds)
{
foreach (var plm in EnumerateLeaderboardModels())
{
var pid = plm.playerId;
var pid = ReadPlatformUserId(plm);
if (!string.IsNullOrEmpty(pid))
{
onDone(pid.Trim());
onDone(pid);
yield break;
}
}
if (waited - lastGetUserInfoAttempt >= PlatformUserGetUserInfoRetrySeconds)
{
lastGetUserInfoAttempt = waited;
var model = ResolvePlatformUserModel();
if (model != null)
{
Task<UserInfo> task;
try
{
task = model.GetUserInfo(CancellationToken.None);
}
catch (Exception)
{
task = null;
}
if (task != null)
{
while (!task.IsCompleted)
{
yield return null;
}
if (!task.IsFaulted)
{
var uid = task.Result?.platformUserId;
if (!string.IsNullOrEmpty(uid))
{
onDone(uid.Trim());
yield break;
}
}
}
}
}
waited += PlatformUserPollStepSeconds;
yield return new WaitForSeconds(PlatformUserPollStepSeconds);
}
@@ -188,26 +148,36 @@ namespace Setlist
}
}
private static IPlatformUserModel ResolvePlatformUserModel()
private static string ReadPlatformUserId(PlatformLeaderboardsModel model)
{
var field = typeof(PlatformLeaderboardsModel).GetField(
"_platformUserModel",
BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
if (model == null)
{
return null;
}
IPlatformUserModel last = null;
foreach (var plm in EnumerateLeaderboardModels())
var id = NormalizeUserId(model.playerId);
if (!string.IsNullOrEmpty(id))
{
if (field.GetValue(plm) is IPlatformUserModel m)
{
last = m;
}
return id;
}
return last;
var platformField = typeof(PlatformLeaderboardsModel).GetField(
"_platform",
BindingFlags.Instance | BindingFlags.NonPublic);
var platform = platformField?.GetValue(model);
var user = platform?.GetType().GetProperty("user")?.GetValue(platform, null);
return NormalizeUserId(user?.GetType().GetProperty("userId")?.GetValue(user, null));
}
private static string NormalizeUserId(object raw)
{
if (raw == null)
{
return null;
}
var value = raw.ToString()?.Trim();
return string.IsNullOrEmpty(value) || value == "0" ? null : value;
}
/// <summary>
+39 -22
View File
@@ -1,8 +1,10 @@
using System;
using System.Collections;
using System.Collections.Generic;
using BeatSaberPlaylistsLib.Types;
using IPA;
using PlaylistManager.Utilities;
using UnityEngine;
using IPALogger = IPA.Logging.Logger;
namespace Setlist
@@ -20,6 +22,9 @@ namespace Setlist
/// <summary>Set after the ownership scan resolves the platform user id; used when syncing after PlaylistManager adds a song.</summary>
internal static string CachedPlatformUserId { get; set; }
private const float PlaylistScanPollStepSeconds = 0.5f;
private const float PlaylistScanWaitTimeoutSeconds = 10f;
[Init]
public Plugin(IPALogger logger)
{
@@ -36,43 +41,55 @@ namespace Setlist
Events.playlistSongAdded += OnPlaylistSongAdded;
SetlistSyncHost.Instance.StartPlaylistOwnershipScan(Log);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
}
}
internal static IEnumerator CoScanAndLogPlaylistOwnership(IPALogger log)
{
var waited = 0f;
while (waited <= PlaylistScanWaitTimeoutSeconds)
{
var playlists = BeatSaberPlaylistsLib.PlaylistManager.DefaultManager.GetAllPlaylists(
includeChildren: true,
out AggregateException loadErrors);
if (loadErrors != null)
{
Log.Error(loadErrors.Message);
log.Error(loadErrors.Message);
foreach (var inner in loadErrors.InnerExceptions)
{
Log.Error(inner.ToString());
log.Error(inner.ToString());
}
}
if (playlists == null || playlists.Length == 0)
if (playlists != null && playlists.Length > 0)
{
Log.Info("No playlists loaded (or playlist library not initialized yet).");
return;
var entries = new List<(IPlaylist Playlist, string Title, bool HasSyncUrl, string BeatLeaderGuid, string OwnerId)>();
foreach (var playlist in playlists)
{
BeatLeaderPlaylistOwnership.TryReadBeatLeaderMetadata(
playlist,
out var hasSyncUrl,
out var blGuid,
out var ownerId);
entries.Add((playlist, playlist.Title, hasSyncUrl, blGuid, ownerId));
}
BeatLeaderPlaylistOwnership.ScheduleVerifyAndLog(entries, log);
yield break;
}
var entries = new List<(IPlaylist Playlist, string Title, bool HasSyncUrl, string BeatLeaderGuid, string OwnerId)>();
foreach (var playlist in playlists)
{
BeatLeaderPlaylistOwnership.TryReadBeatLeaderMetadata(
playlist,
out var hasSyncUrl,
out var blGuid,
out var ownerId);
entries.Add((playlist, playlist.Title, hasSyncUrl, blGuid, ownerId));
}
BeatLeaderPlaylistOwnership.ScheduleVerifyAndLog(entries, Log);
}
catch (Exception ex)
{
Log.Error(ex.ToString());
waited += PlaylistScanPollStepSeconds;
yield return new WaitForSeconds(PlaylistScanPollStepSeconds);
}
log.Info("No playlists loaded after startup wait.");
}
[OnExit]
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: Guid("50F53E6E-21D5-4780-8E67-273877DAA28C")]
[assembly: AssemblyVersion("0.1.0.0")]
[assembly: AssemblyFileVersion("0.1.0.0")]
[assembly: AssemblyVersion("0.1.1.0")]
[assembly: AssemblyFileVersion("0.1.1.0")]
+5
View File
@@ -28,5 +28,10 @@ namespace Setlist
{
StartCoroutine(BeatLeaderPlaylistSync.CoPostOwnedPlaylistToBeatLeader(playlist, log));
}
internal void StartPlaylistOwnershipScan(IPALogger log)
{
StartCoroutine(Plugin.CoScanAndLogPlaylistOwnership(log));
}
}
}
+3 -3
View File
@@ -3,13 +3,13 @@
"id": "Setlist",
"name": "Setlist",
"author": "",
"version": "0.1.0",
"version": "0.1.1",
"description": "Syncs playlists with external sources.",
"gameVersion": "1.40.8",
"gameVersion": "1.44.1",
"dependsOn": {
"BSIPA": "^4.3.0",
"BeatSaberPlaylistsLib": "^1.7.0",
"BeatLeader": "^0.9.0",
"BeatLeader": ">=0.9.0",
"PlaylistManager": "^1.7.0"
}
}