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
@@ -56,7 +56,7 @@ namespace PrivaPub.Federation.Objects
|
||||
|
||||
public static class NoteParser
|
||||
{
|
||||
static readonly string[] NoteTypes = { "Note", "Article", "Page", "Question", "Event", "Video", "Audio", "Image", "ChatMessage" };
|
||||
static readonly string[] NoteTypes = { "Note", "Article", "Page", "Question", "Event", "Video", "Audio", "Image", "ChatMessage", "PodcastEpisode" };
|
||||
const int MaxAttachments = 16;
|
||||
const int MaxTags = 64;
|
||||
|
||||
@@ -68,6 +68,8 @@ namespace PrivaPub.Federation.Objects
|
||||
var id = Id(note);
|
||||
if (!NoteTypes.Contains(type) || Origin.Of(id) == default)
|
||||
return default;
|
||||
if (type == "PodcastEpisode")
|
||||
note = Episode(note);
|
||||
|
||||
var (contentHtml, language) = Content(note);
|
||||
var summary = Value(note, "summary");
|
||||
@@ -123,13 +125,32 @@ namespace PrivaPub.Federation.Objects
|
||||
CoverURL = ObjectShapes.Cover(note),
|
||||
Link = ObjectShapes.Link(note),
|
||||
Video = ObjectShapes.Video(note),
|
||||
Audio = ObjectShapes.Audio(note),
|
||||
Audio = ObjectShapes.Audio(type == "PodcastEpisode" ? note["audio"] as JsonObject : note),
|
||||
Event = ObjectShapes.Event(note),
|
||||
Place = ObjectShapes.NotePlace(note),
|
||||
CommentsEnabled = note["commentsEnabled"] is JsonValue comments && comments.TryGetValue<bool>(out var enabled) ? enabled : null
|
||||
};
|
||||
}
|
||||
|
||||
// Castopod's PodcastEpisode: its words in `description` (a Note of its own), its sound in `audio`, its title the
|
||||
// sound's name; read as a post with those
|
||||
static JsonObject Episode(JsonObject episode)
|
||||
{
|
||||
var note = episode.DeepClone().AsObject();
|
||||
if (note["description"] is JsonObject description)
|
||||
{
|
||||
note["content"] = description["content"]?.DeepClone();
|
||||
note["contentMap"] = description["contentMap"]?.DeepClone();
|
||||
note["mediaType"] = description["mediaType"]?.DeepClone();
|
||||
}
|
||||
if (note["audio"] is JsonObject audio)
|
||||
{
|
||||
note["name"] ??= audio["name"]?.DeepClone();
|
||||
note["attachment"] = new JsonArray(audio.DeepClone());
|
||||
}
|
||||
return note;
|
||||
}
|
||||
|
||||
static (string Html, string Language) Content(JsonObject note)
|
||||
{
|
||||
var content = Value(note, "content");
|
||||
|
||||
Reference in new issue
Block a user