Posts for later, hashtags followed, and Explore

The composer's clock button gives a post a time (scheduled_at, at least five
minutes ahead; located and group posts have none), and /scheduled moves or
drops what waits. A hashtag's feed tab shows its week and follows it, so its
public posts come home. Explore (/explore) shows what PrivaPub says is
trending, hashtags, posts and links from public posts it holds, the
directory by activity or by joining, and the hashtags the persona follows.
DiscoveryService does the calls; the e2e tests check each against PrivaPub's
own answer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
thepraandClaude Opus 5.5 committed 2026-10-05 03:53:51 +02:00
1 parent 9a752d9288
commit 6d5cf17723
17 files changed
+1001 -7

No files matched your search

+10
View File
@@ -70,6 +70,16 @@ public static class APIs
public static string M_ListAccounts(string listId) => $"api/v1/lists/{Uri.EscapeDataString(listId)}/accounts";
public static string GET_M_AccountLists(string accountId) => $"api/v1/accounts/{Uri.EscapeDataString(accountId)}/lists";
public static string GET_M_ListTimeline(string listId) => $"api/v1/timelines/list/{Uri.EscapeDataString(listId)}";
public const string GET_ScheduledStatuses = "api/v1/scheduled_statuses";
public const string GET_FollowedTags = "api/v1/followed_tags";
public const string GET_TrendingTags = "api/v1/trends/tags";
public const string GET_TrendingStatuses = "api/v1/trends/statuses";
public const string GET_TrendingLinks = "api/v1/trends/links";
public const string GET_Directory = "api/v1/directory";
public static string GET_M_Tag(string name) => $"api/v1/tags/{Uri.EscapeDataString(name)}";
public static string POST_M_TagAction(string name, string action) => $"api/v1/tags/{Uri.EscapeDataString(name)}/{action}";
public static string PUT_M_ScheduledStatus(string id) => $"api/v1/scheduled_statuses/{Uri.EscapeDataString(id)}";
public static string DELETE_M_ScheduledStatus(string id) => $"api/v1/scheduled_statuses/{Uri.EscapeDataString(id)}";
public const string GET_Filters = "api/v2/filters";
public const string POST_Filter = "api/v2/filters";
public static string PUT_M_Filter(string filterId) => $"api/v2/filters/{Uri.EscapeDataString(filterId)}";
+8
View File
@@ -37,6 +37,14 @@ public class ComposeForm
public double? Latitude { get; set; }
public double? Longitude { get; set; }
/// <summary>Whether the post waits for ScheduledAt (a datetime-local value, the reader's own time) instead of going now.</summary>
public bool IsScheduled { get; set; }
public string ScheduledAt { get; set; }
/// <summary>When the post is to be published, in UTC, or null when it goes now or ScheduledAt is not a time.</summary>
public DateTime? ScheduledAtUtc => IsScheduled && DateTime.TryParse(ScheduledAt, System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.AssumeLocal, out var local) ? local.ToUniversalTime() : null;
[JsonIgnore, Bindable(false)]
public MediaType MediaType { get; set; } = MediaType.Images;
[JsonIgnore, Bindable(false)]
+33
View File
@@ -0,0 +1,33 @@
namespace decePubClient.Models.Mastodon;
/// <summary>A hashtag as PrivaPub describes it: its last week of use in public posts it holds, and whether the persona
/// follows it (null when nobody is signed in).</summary>
public class Tag
{
public string Name { get; set; }
public string Url { get; set; }
public List<TagDay> History { get; set; } = [];
public bool? Following { get; set; }
public int WeekUses => History.Sum(h => h.UsesCount);
public int TodayAccounts => History.FirstOrDefault()?.AccountsCount ?? 0;
}
/// <summary>One day of a tag's or a link's use; Mastodon sends the numbers as strings, the day as unix time.</summary>
public class TagDay
{
public string Day { get; set; }
public string Uses { get; set; }
public string Accounts { get; set; }
public int UsesCount => int.TryParse(Uses, out var n) ? n : 0;
public int AccountsCount => int.TryParse(Accounts, out var n) ? n : 0;
}
/// <summary>A link many authors shared this week: its preview card with its days.</summary>
public class TrendLink : PreviewCard
{
public List<TagDay> History { get; set; } = [];
public int WeekAccounts => History.Sum(h => h.AccountsCount);
}
+24
View File
@@ -176,4 +176,28 @@ public class PostStatusForm
public string SpoilerText { get; set; }
public string Visibility { get; set; }
public string Language { get; set; }
/// <summary>When the post is to be published (ISO 8601, at least five minutes ahead); null posts it now.</summary>
public string ScheduledAt { get; set; }
}
/// <summary>A post waiting for its time (/api/v1/scheduled_statuses).</summary>
public class ScheduledStatus
{
public string Id { get; set; }
public DateTime ScheduledAt { get; set; }
public ScheduledParams Params { get; set; } = new();
public List<MediaAttachment> MediaAttachments { get; set; } = [];
}
public class ScheduledParams
{
public string Text { get; set; }
public string SpoilerText { get; set; }
public string Visibility { get; set; }
public string InReplyToId { get; set; }
}
public class ScheduleForm
{
public string ScheduledAt { get; set; }
}