BSDataPuller
BSDataPuller copied to clipboard
[Fix/Feature Request] CoverImage for non-BeatSaver songs
I have a working build that just copies the texture-reading code from HTTP Status, but I don't think it's pull-request-worthy.
diff --git a/src/Core/MapEvents.cs b/src/Core/MapEvents.cs
index 4dbbc91..55fa3db 100644
--- a/src/Core/MapEvents.cs
+++ b/src/Core/MapEvents.cs
@@ -178,7 +178,7 @@ namespace DataPuller.Core
MapData.Instance.Send();
}
- public void LevelLoaded()
+ public async void LevelLoaded()
{
PlayerData playerData = Resources.FindObjectsOfTypeAll<PlayerDataModel>().FirstOrDefault().playerData;
IBeatmapLevel levelData = gameplayCoreSceneSetupData.difficultyBeatmap.level;
@@ -204,6 +204,40 @@ namespace DataPuller.Core
MapData.Instance.Difficulty = gameplayCoreSceneSetupData.difficultyBeatmap.difficulty.ToString("g");
MapData.Instance.NJS = gameplayCoreSceneSetupData.difficultyBeatmap.noteJumpMovementSpeed;
MapData.Instance.CustomDifficultyLabel = difficultyData?._difficultyLabel ?? null;
+
+ // From HTTPStatus
+ try {
+ // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures-
+ // Modified to correctly handle texture atlases. Fixes #82.
+ var active = RenderTexture.active;
+
+ var sprite = await levelData.GetCoverImageAsync(System.Threading.CancellationToken.None);
+ var texture = sprite.texture;
+ var temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear);
+
+ Graphics.Blit(texture, temporary);
+ RenderTexture.active = temporary;
+
+ var spriteRect = sprite.rect;
+ var uv = sprite.uv[0];
+
+ var cover = new Texture2D((int) spriteRect.width, (int) spriteRect.height);
+ // Unity sucks. The coordinates of the sprite on its texture atlas are only accessible through the Sprite.uv property since rect always returns `x=0,y=0`, so we need to convert them back into texture space.
+ cover.ReadPixels(new Rect(
+ uv.x * texture.width,
+ texture.height - uv.y * texture.height,
+ spriteRect.width,
+ spriteRect.height
+ ), 0, 0);
+ cover.Apply();
+
+ RenderTexture.active = active;
+ RenderTexture.ReleaseTemporary(temporary);
+
+ MapData.Instance.CoverImage = "data:image/png;base64," + System.Convert.ToBase64String(ImageConversion.EncodeToPNG(cover));
+ } catch {
+ MapData.Instance.CoverImage = null;
+ }
if (isCustomLevel)
{
@@ -267,7 +301,6 @@ namespace DataPuller.Core
else
{
MapData.Instance.BSRKey = null;
- MapData.Instance.CoverImage = null;
}
MapData.Instance.Send();
});
For what it's worth, I have fixed this as of v2.1.11 in my fork using your solution as a base