171 lines
No EOL
6.1 KiB
C#
171 lines
No EOL
6.1 KiB
C#
using System.Net.Mime;
|
|
using System.ServiceModel.Syndication;
|
|
using System.Text.Json.Serialization;
|
|
using System.Xml;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using PancakesWeb.Components.UI;
|
|
using J = System.Text.Json.Serialization.JsonPropertyNameAttribute;
|
|
using JI = System.Text.Json.Serialization.JsonIgnoreAttribute;
|
|
|
|
namespace PancakesWeb.Controllers;
|
|
|
|
[ApiController]
|
|
public class FeedController : ControllerBase
|
|
{
|
|
[HttpGet("/feed.atom")]
|
|
[Produces("application/atom+xml")]
|
|
public ContentResult GetAtomFeed()
|
|
{
|
|
var feed = new SyndicationFeed
|
|
{
|
|
Title = new TextSyndicationContent("pancakes' blog"),
|
|
Description = new TextSyndicationContent("🐈⬛"),
|
|
Id = "https://pancakes.gay/feed.atom",
|
|
BaseUri = new Uri("https://pancakes.gay/feed.atom"),
|
|
Authors = { new SyndicationPerson("p@pancakes.gay", "pancakes", "https://pancakes.gay") },
|
|
Items = BlogPosts.Posts.OrderByDescending(post => post.Published).Select(post =>
|
|
new SyndicationItem(post.Title, SyndicationContent.CreateHtmlContent(post.Content),
|
|
new Uri($"https://pancakes.gay/{post.Slug}"), $"https://pancakes.gay/{post.Slug}",
|
|
new DateTimeOffset(post.Edited ?? post.Published))
|
|
{
|
|
Copyright = post.Footer is BlogPosts.PostFooter.CcBy
|
|
? new TextSyndicationContent(
|
|
$"{post.Title} © {post.Published.Year} by pancakes is licensed under CC BY 4.0")
|
|
: null,
|
|
PublishDate = new DateTimeOffset(post.Published),
|
|
Summary = new TextSyndicationContent(post.Description)
|
|
}),
|
|
Links =
|
|
{
|
|
SyndicationLink.CreateSelfLink(new Uri("https://pancakes.gay/feed.atom")),
|
|
SyndicationLink.CreateAlternateLink(new Uri("https://pancakes.gay"), MediaTypeNames.Text.Html),
|
|
}
|
|
};
|
|
|
|
var stringWriter = new StringWriter();
|
|
var writer = new XmlTextWriter(stringWriter);
|
|
feed.SaveAsAtom10(writer);
|
|
|
|
return Content(stringWriter.ToString(), "application/atom+xml");
|
|
}
|
|
|
|
[HttpGet("/feed.json")]
|
|
[Produces("application/feed+json", MediaTypeNames.Application.Json)]
|
|
public JsonFeed GetJsonFeed() => new JsonFeed
|
|
{
|
|
Title = "pancakes' blog",
|
|
HomePageUrl = "https://pancakes.gay",
|
|
FeedUrl = "https://pancakes.gay/feed.json",
|
|
Description = "🐈⬛",
|
|
Icon = "https://pancakes.gay/icon.webp",
|
|
Favicon = "https://pancakes.gay/favicon.ico",
|
|
Authors =
|
|
[
|
|
new JsonFeedAuthor
|
|
{
|
|
Name = "pancakes",
|
|
Url = "https://pancakes.gay",
|
|
Avatar = "https://pancakes.gay/icon.webp"
|
|
}
|
|
],
|
|
Language = "en",
|
|
Items = BlogPosts.Posts.OrderByDescending(post => post.Published).Select(post => new JsonFeedItem
|
|
{
|
|
Id = $"https://pancakes.gay/{post.Slug}",
|
|
Url = $"https://pancakes.gay/{post.Slug}",
|
|
Title = post.Title,
|
|
ContentHtml = post.Content,
|
|
Summary = post.Description,
|
|
BannerImage = $"https://pancakes.gay/post-assets/{post.Slug}/{post.HeaderFilename}",
|
|
DatePublished = post.Published,
|
|
DateModified = post.Edited,
|
|
Tags = null
|
|
}).ToList()
|
|
};
|
|
|
|
public class JsonFeed
|
|
{
|
|
[J("version")] public string Version => "https://jsonfeed.org/version/1.1";
|
|
[J("title")] public required string Title { get; set; }
|
|
|
|
[J("home_page_url")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? HomePageUrl { get; set; }
|
|
|
|
[J("feed_url")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? FeedUrl { get; set; }
|
|
|
|
[J("description")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Description { get; set; }
|
|
|
|
[J("icon")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Icon { get; set; }
|
|
|
|
[J("favicon")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Favicon { get; set; }
|
|
|
|
[J("authors")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public List<JsonFeedAuthor>? Authors { get; set; }
|
|
|
|
[J("language")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Language { get; set; }
|
|
|
|
[J("items")] public List<JsonFeedItem> Items { get; set; } = [];
|
|
}
|
|
|
|
public class JsonFeedAuthor
|
|
{
|
|
[J("name")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Name { get; set; }
|
|
|
|
[J("url")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Url { get; set; }
|
|
|
|
[J("avatar")]
|
|
[JI(Condition = JsonIgnoreCondition.Never)]
|
|
public string? Avatar { get; set; }
|
|
}
|
|
|
|
public class JsonFeedItem
|
|
{
|
|
[J("id")] public required string Id { get; set; }
|
|
|
|
[J("url")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Url { get; set; }
|
|
|
|
[J("title")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Title { get; set; }
|
|
|
|
[J("content_html")] public required string ContentHtml { get; set; }
|
|
|
|
[J("summary")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? Summary { get; set; }
|
|
|
|
[J("banner_image")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public string? BannerImage { get; set; }
|
|
|
|
[J("date_published")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public DateTime? DatePublished { get; set; }
|
|
|
|
[J("date_modified")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public DateTime? DateModified { get; set; }
|
|
|
|
[J("tags")]
|
|
[JI(Condition = JsonIgnoreCondition.WhenWritingNull)]
|
|
public List<string>? Tags { get; set; }
|
|
}
|
|
} |