using decePubClient.Models.Mastodon; namespace decePubClient.Models; /// /// One item of a feed, whatever its source: a status (a boost shows its original, BoostedBy names the booster), a /// notification, a direct conversation, or a located post from /clientapi/post/nearby (Located, with no Mastodon /// actions: PrivaPub keeps those posts off the Mastodon API). Location is filled by InstanceService once the author's /// server is known. /// public class FeedPost { /// Unique within a feed: the status, notification or conversation id. public string Key { get; init; } /// The id the feed pages by (max_id/min_id). public string CursorId { get; init; } /// The post shown; null for a notification without one (a follow). public Status Status { get; set; } public Account BoostedBy { get; init; } public Notification Notification { get; init; } public Conversation Conversation { get; init; } /// A located post: within its range of the reader, never on the Mastodon API. public bool Located { get; init; } public double? DistanceKm { get; init; } public double? RangeKm { get; init; } public FeedLocation Location { get; set; } /// The account the item is about: the post's author, or whoever caused the notification. public Account Author => Status?.Account ?? Notification?.Account; public string Host => Author?.Host; public bool IsOwnedBy(string personaId) => personaId is not null && Status?.Account?.Id == personaId; public static FeedPost Of(Status status) => status.Reblog is { } original ? new() { Key = status.Id, CursorId = status.Id, Status = original, BoostedBy = status.Account } : new() { Key = status.Id, CursorId = status.Id, Status = status }; public static FeedPost Of(Notification notification) => new() { Key = notification.Id, CursorId = notification.Id, Status = notification.Status?.Reblog ?? notification.Status, Notification = notification }; public static FeedPost Of(Conversation conversation) => new() { Key = conversation.Id, CursorId = conversation.LastStatus?.Id, Status = conversation.LastStatus, Conversation = conversation }; } /// Where a feed item is drawn on the globe, and how sure that is. public enum LocationSource { /// The post's own place (Pixelfed): exact. Place, /// An event's venue: exact. Event, /// The author's server, to 0.1°. Server, /// The author's server, known only by country: a point in that country. Country, /// A located post, within its range of the reader: drawn at the reader. NearYou } public sealed record FeedLocation(double Latitude, double Longitude, LocationSource Source, string Label, double PrecisionKm); /// What the client keeps about a server (from /api/privapub/v1/instances), cached for a day. public class ServerInfo { public string Host { get; set; } public string Software { get; set; } public string Version { get; set; } public string NodeName { get; set; } public bool? OpenRegistrations { get; set; } public long? Users { get; set; } public long? ActiveMonth { get; set; } public long? LocalPosts { get; set; } public InstanceLocation Geo { get; set; } public int ConsecutiveFailures { get; set; } public DateTime? LastSuccessAt { get; set; } public DateTime? LastFailureAt { get; set; } public DateTime? DescribedAt { get; set; } public string DescriptionError { get; set; } public DateTime FetchedAt { get; set; } /// True when PrivaPub did not know the server: nothing to show, asked again later. public bool Unknown { get; set; } } /// A page of a feed and the cursors around it. public class FeedPage { public List Posts { get; set; } = []; /// Older items start below this id; null at the end of the feed. public string MaxId { get; set; } /// Newer items start above this id. public string MinId { get; set; } }