Podcast episodes play; servers with NodeInfo2 only are described
Castopod announces an episode with a Note that only links to the episode's page, which serves a PodcastEpisode. PrivaPub reads PodcastEpisode (its words in description, its sound in audio, its cover in image), and a Note that is only a link to its author's own episode takes the episode's sound, title, cover and words, so the post plays. A server that publishes no NodeInfo is described from NodeInfo2 (/.well-known/x-nodeinfo2), as Castopod publishes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LsXgEaXee4GCU1hwYgPJXw
This commit is contained in:
1 parent
3df3c333bf
commit
69ab8e50eb
7 files changed
+163
-3
No files matched your search
@@ -83,7 +83,7 @@ namespace PrivaPub.Federation.Inbox
|
||||
{
|
||||
var mentions = await Mentions(note, to.Concat(cc), _localActors, token);
|
||||
|
||||
return new PostEntity
|
||||
var post = new PostEntity
|
||||
{
|
||||
ID = PrivacyIds.Arrived(note.Published),
|
||||
ObjectURI = note.Id,
|
||||
@@ -135,6 +135,31 @@ namespace PrivaPub.Federation.Inbox
|
||||
UpdateDate = note.Updated ?? note.Published,
|
||||
EditedAt = note.Updated
|
||||
};
|
||||
await Episode(post, note, author, token);
|
||||
return post;
|
||||
}
|
||||
|
||||
static readonly System.Text.RegularExpressions.Regex Href = new(@"href=""([^""]+)""", System.Text.RegularExpressions.RegexOptions.Compiled);
|
||||
|
||||
// a post that is only a link to a podcast episode of its own author (Castopod announces each episode so): the
|
||||
// episode's sound, title and cover, read from it
|
||||
async Task Episode(PostEntity post, NoteDocument note, ForeignAvatar author, CancellationToken token)
|
||||
{
|
||||
if (note.Type != "Note" || post.Media.Count > 0 || string.IsNullOrEmpty(note.ContentHtml))
|
||||
return;
|
||||
var links = Href.Matches(note.ContentHtml).Select(m => System.Net.WebUtility.HtmlDecode(m.Groups[1].Value)).Distinct().ToList();
|
||||
if (links.Count != 1 || links[0] == note.Id || !Origin.Same(links[0], author.ActorURI))
|
||||
return;
|
||||
using var scope = HttpScope.For("object");
|
||||
using var fetched = await _remoteActors.FetchObject(links[0], token);
|
||||
var episode = fetched == default ? default : NoteParser.Parse(JsonNode.Parse(fetched.Root.GetRawText()));
|
||||
if (episode is not { Type: "PodcastEpisode" } || episode.AttributedTo != author.ActorURI)
|
||||
return;
|
||||
post.Media = episode.Attachments.ToList();
|
||||
post.Audio = episode.Audio;
|
||||
post.Title ??= episode.Title;
|
||||
post.CoverURL ??= episode.CoverURL;
|
||||
post.Excerpt ??= ObjectShapes.Text(episode.ContentHtml, 1000);
|
||||
}
|
||||
|
||||
public async Task<PostEntity> Parent(string inReplyTo, int depth, CancellationToken token)
|
||||
|
||||
Reference in new issue
Block a user