float.TryParse takes "NaN" and "Infinity", and Math.Clamp keeps a NaN, so `focus=NaN,NaN` on an upload or a media PUT was stored as given. Once the media was posted, every status and timeline response holding the post, and the Note and its delivery, failed to serialise, for every viewer. FocalPoint.Parse takes finite numbers only (anything else is ignored, as an unreadable focus was); the mapper and the renderer leave out a focus that isn't sound, and migration _016 removes the ones stored before, from the uploads and from the copy each post keeps. What PrivaPub sends is unchanged for any focus that could be sent before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
22 lines
946 B
C#
22 lines
946 B
C#
using System.Globalization;
|
|
|
|
namespace PrivaPub.Domain.Media
|
|
{
|
|
// A focal point as Mastodon's API takes it ("x,y", each within -1..1): finite numbers only, clamped to the frame. A NaN
|
|
// once stored here made every status, timeline and Note holding the post fail to serialise, for every viewer.
|
|
public static class FocalPoint
|
|
{
|
|
public static float[] Parse(string value)
|
|
{
|
|
if (value?.Split(',') is not [var x, var y]
|
|
|| !float.TryParse(x, NumberStyles.Float, CultureInfo.InvariantCulture, out var fx) || !float.IsFinite(fx)
|
|
|| !float.TryParse(y, NumberStyles.Float, CultureInfo.InvariantCulture, out var fy) || !float.IsFinite(fy))
|
|
return default;
|
|
return [Math.Clamp(fx, -1, 1), Math.Clamp(fy, -1, 1)];
|
|
}
|
|
|
|
/// <summary>Whether a stored focal point can be written out: two finite numbers.</summary>
|
|
public static bool IsSound(float[] focus) => focus is [var x, var y] && float.IsFinite(x) && float.IsFinite(y);
|
|
}
|
|
}
|