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,
/// The author's server is behind a CDN, whose address says nothing of its place: drawn with the CDN's group.
Cdn
}
///
/// Where a feed item is drawn. For a CDN-fronted server (Source Cdn) Latitude/Longitude mean nothing: the globe groups it
/// under CdnKey, and Before is where the server was before the CDN, when PrivaPub saw it.
///
public sealed record FeedLocation(double Latitude, double Longitude, LocationSource Source, string Label, double PrecisionKm, string CdnKey = default,
InstancePlace Before = default)
{
public bool HasPoint => Source is not LocationSource.Cdn;
}
/// 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; }
}