From 2394f03b3b2013f9c387c50076fc412bc077e0c7 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sat, 4 Jun 2022 20:49:14 -0400 Subject: [PATCH] - Fix a few issues with podcast feed generation - Tweak styles for devotional theme - Fix bug with page cache building --- src/MyWebLog.Domain/DataTypes.fs | 11 +++-- src/MyWebLog/Caches.fs | 5 +- src/MyWebLog/Handlers/Feed.fs | 52 +++++++++++++++----- src/MyWebLog/Handlers/Post.fs | 5 +- src/MyWebLog/appsettings.json | 2 +- src/MyWebLog/themes/awftw/index.liquid | 6 +-- src/MyWebLog/themes/awftw/single-page.liquid | 1 + src/MyWebLog/themes/awftw/single-post.liquid | 11 +---- src/MyWebLog/wwwroot/themes/awftw/style.css | 13 ++++- 9 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/MyWebLog.Domain/DataTypes.fs b/src/MyWebLog.Domain/DataTypes.fs index 7c1cb1f..49c232e 100644 --- a/src/MyWebLog.Domain/DataTypes.fs +++ b/src/MyWebLog.Domain/DataTypes.fs @@ -312,10 +312,15 @@ module WebLog = let _, leadPath = hostAndPath webLog $"{leadPath}/{Permalink.toString permalink}" - /// Convert a date/time to the web log's local date/time + /// Convert a UTC date/time to the web log's local date/time let localTime webLog (date : DateTime) = - let tz = TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone - TimeZoneInfo.ConvertTimeFromUtc (DateTime (date.Ticks, DateTimeKind.Utc), tz) + TimeZoneInfo.ConvertTimeFromUtc + (DateTime (date.Ticks, DateTimeKind.Utc), TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone) + + /// Convert a date/time in the web log's local date/time to UTC + let utcTime webLog (date : DateTime) = + TimeZoneInfo.ConvertTimeToUtc + (DateTime (date.Ticks, DateTimeKind.Unspecified), TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone) /// A user of the web log diff --git a/src/MyWebLog/Caches.fs b/src/MyWebLog/Caches.fs index 2fd0b1e..bec985c 100644 --- a/src/MyWebLog/Caches.fs +++ b/src/MyWebLog/Caches.fs @@ -65,7 +65,10 @@ module PageListCache = let update (ctx : HttpContext) = backgroundTask { let webLog = ctx.WebLog let! pages = Data.Page.findListed webLog.id ctx.Conn - _cache[webLog.urlBase] <- pages |> List.map (DisplayPage.fromPage webLog) |> Array.ofList + _cache[webLog.urlBase] <- + pages + |> List.map (fun pg -> DisplayPage.fromPage webLog { pg with text = "" }) + |> Array.ofList } diff --git a/src/MyWebLog/Handlers/Feed.fs b/src/MyWebLog/Handlers/Feed.fs index 0313105..6521421 100644 --- a/src/MyWebLog/Handlers/Feed.fs +++ b/src/MyWebLog/Handlers/Feed.fs @@ -95,9 +95,18 @@ let private toFeedItem webLog (authors : MetaItem list) (cats : DisplayCategory[ Content = TextSyndicationContent.CreatePlaintextContent plainText) item.AddPermalink (Uri item.Id) + let xmlDoc = XmlDocument () + let encoded = - post.text.Replace("src=\"/", $"src=\"{webLog.urlBase}/").Replace ("href=\"/", $"href=\"{webLog.urlBase}/") - item.ElementExtensions.Add ("encoded", Namespace.content, encoded) + let txt = + post.text + .Replace("src=\"/", $"src=\"{webLog.urlBase}/") + .Replace ("href=\"/", $"href=\"{webLog.urlBase}/") + let it = xmlDoc.CreateElement ("content", "encoded", Namespace.content) + let _ = it.AppendChild (xmlDoc.CreateCDataSection txt) + it + item.ElementExtensions.Add encoded + item.Authors.Add (SyndicationPerson ( Name = (authors |> List.find (fun a -> a.name = WebLogUserId.toString post.authorId)).value)) [ post.categoryIds @@ -124,6 +133,7 @@ let private addEpisode webLog (feed : CustomFeed) (post : Post) (item : Syndicat let epMediaUrl = match (meta >> Option.get >> value) "episode_media_file" with | link when link.StartsWith "http" -> link + | link when Option.isSome podcast.mediaBaseUrl -> $"{podcast.mediaBaseUrl.Value}{link}" | link -> WebLog.absoluteUrl webLog (Permalink link) let epMediaType = match meta "episode_media_type", podcast.defaultMediaType with @@ -142,16 +152,22 @@ let private addEpisode webLog (feed : CustomFeed) (post : Post) (item : Syndicat with :? ArgumentException -> ExplicitRating.toString podcast.explicit let xmlDoc = XmlDocument () - let enclosure = xmlDoc.CreateElement "enclosure" - enclosure.SetAttribute ("url", epMediaUrl) - meta "episode_media_length" |> Option.iter (fun it -> enclosure.SetAttribute ("length", it.value)) - epMediaType |> Option.iter (fun typ -> enclosure.SetAttribute ("type", typ)) + let enclosure = + let it = xmlDoc.CreateElement "enclosure" + it.SetAttribute ("url", epMediaUrl) + meta "episode_media_length" |> Option.iter (fun len -> it.SetAttribute ("length", len.value)) + epMediaType |> Option.iter (fun typ -> it.SetAttribute ("type", typ)) + it + let image = + let it = xmlDoc.CreateElement ("itunes", "image", Namespace.iTunes) + it.SetAttribute ("href", epImageUrl) + it + item.ElementExtensions.Add enclosure - + item.ElementExtensions.Add image item.ElementExtensions.Add ("creator", Namespace.dc, podcast.displayedAuthor) item.ElementExtensions.Add ("author", Namespace.iTunes, podcast.displayedAuthor) item.ElementExtensions.Add ("summary", Namespace.iTunes, stripHtml post.text) - item.ElementExtensions.Add ("image", Namespace.iTunes, epImageUrl) item.ElementExtensions.Add ("explicit", Namespace.iTunes, epExplicit) meta "episode_subtitle" |> Option.iter (fun it -> item.ElementExtensions.Add ("subtitle", Namespace.iTunes, it.value)) @@ -218,21 +234,30 @@ let private addPodcast webLog (rssFeed : SyndicationFeed) (feed : CustomFeed) = "link", feedUrl ] |> List.fold (fun elt (name, value) -> addChild xmlDoc "" "" name value elt) (xmlDoc.CreateElement "image") + let iTunesImage = + let it = xmlDoc.CreateElement ("itunes", "image", Namespace.iTunes) + it.SetAttribute ("href", imageUrl) + it let owner = [ "name", podcast.displayedAuthor "email", podcast.email ] |> List.fold (fun elt (name, value) -> addChild xmlDoc Namespace.iTunes "itunes" name value elt) (xmlDoc.CreateElement ("itunes", "owner", Namespace.iTunes)) + let rawVoice = + let it = xmlDoc.CreateElement ("rawvoice", "subscribe", Namespace.rawVoice) + it.SetAttribute ("feed", feedUrl) + it.SetAttribute ("itunes", "") + it rssFeed.ElementExtensions.Add image rssFeed.ElementExtensions.Add owner rssFeed.ElementExtensions.Add categorization + rssFeed.ElementExtensions.Add iTunesImage + rssFeed.ElementExtensions.Add rawVoice rssFeed.ElementExtensions.Add ("summary", Namespace.iTunes, podcast.summary) rssFeed.ElementExtensions.Add ("author", Namespace.iTunes, podcast.displayedAuthor) - rssFeed.ElementExtensions.Add ("image", Namespace.iTunes, imageUrl) rssFeed.ElementExtensions.Add ("explicit", Namespace.iTunes, ExplicitRating.toString podcast.explicit) - rssFeed.ElementExtensions.Add ("subscribe", Namespace.rawVoice, feedUrl) podcast.subtitle |> Option.iter (fun sub -> rssFeed.ElementExtensions.Add ("subtitle", Namespace.iTunes, sub)) /// Get the feed's self reference and non-feed link @@ -241,9 +266,10 @@ let private selfAndLink webLog feedType = | StandardFeed path -> path | CategoryFeed (_, path) -> path | TagFeed (_, path) -> path + // TODO: get defined path for custom feed | Custom (_, path) -> path |> function - | path -> Permalink path, Permalink (path.Replace ($"/{webLog.rss.feedName}", "")) + | path -> Permalink path[1..], Permalink (path.Replace ($"/{webLog.rss.feedName}", "")) /// Set the title and description of the feed based on its source let private setTitleAndDescription feedType (webLog : WebLog) (cats : DisplayCategory[]) (feed : SyndicationFeed) = @@ -287,7 +313,7 @@ let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backg let toItem post = let item = toFeedItem webLog authors cats tagMaps post match podcast with - | Some feed when post.metadata |> List.exists (fun it -> it.name = "media") -> + | Some feed when post.metadata |> List.exists (fun it -> it.name = "episode_media_file") -> addEpisode webLog feed post item | Some _ -> warn "Feed" ctx $"[{webLog.name} {Permalink.toString self}] \"{stripHtml post.title}\" has no media" @@ -298,7 +324,7 @@ let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backg addNamespace feed "content" Namespace.content setTitleAndDescription feedType webLog cats feed - feed.LastUpdatedTime <- DateTimeOffset <| (List.head posts).updatedOn + feed.LastUpdatedTime <- (List.head posts).updatedOn |> DateTimeOffset feed.Generator <- generator ctx feed.Items <- posts |> Seq.ofList |> Seq.map toItem feed.Language <- "en" diff --git a/src/MyWebLog/Handlers/Post.fs b/src/MyWebLog/Handlers/Post.fs index 9c29517..4141f8e 100644 --- a/src/MyWebLog/Handlers/Post.fs +++ b/src/MyWebLog/Handlers/Post.fs @@ -336,10 +336,7 @@ let save : HttpHandler = fun next ctx -> task { let post = match model.setPublished with | true -> - let dt = - TimeZoneInfo.ConvertTimeToUtc - (DateTime (model.pubOverride.Value.Ticks, DateTimeKind.Unspecified), - TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone) + let dt = WebLog.utcTime webLog model.pubOverride.Value match model.setUpdated with | true -> { post with diff --git a/src/MyWebLog/appsettings.json b/src/MyWebLog/appsettings.json index c27ae56..4c7d3f0 100644 --- a/src/MyWebLog/appsettings.json +++ b/src/MyWebLog/appsettings.json @@ -3,7 +3,7 @@ "hostname": "data02.bitbadger.solutions", "database": "myWebLog_dev" }, - "Generator": "myWebLog 2.0-alpha30", + "Generator": "myWebLog 2.0-alpha31", "Logging": { "LogLevel": { "MyWebLog.Handlers": "Debug" diff --git a/src/MyWebLog/themes/awftw/index.liquid b/src/MyWebLog/themes/awftw/index.liquid index 3dd1b1a..23a290f 100644 --- a/src/MyWebLog/themes/awftw/index.liquid +++ b/src/MyWebLog/themes/awftw/index.liquid @@ -19,10 +19,8 @@

- {{ post.published_on | date: "dddd, MMMM d, yyyy" }}   - {% comment %} TODO: reading time? - #[i.fa.fa-clock-o(title='Clock' aria-hidden='true')] #[= readingTime(post.content, 'minutes', 175)] - {% endcomment %} + {{ post.published_on | date: "dddd, MMMM d, yyyy" }} + {% if logged_on %} • Edit Post{% endif %}

{%- assign media = post.metadata | value: "episode_media_file" -%} {%- unless media == "-- episode_media_file not found --" %} diff --git a/src/MyWebLog/themes/awftw/single-page.liquid b/src/MyWebLog/themes/awftw/single-page.liquid index 869038e..73ca95f 100644 --- a/src/MyWebLog/themes/awftw/single-page.liquid +++ b/src/MyWebLog/themes/awftw/single-page.liquid @@ -1,6 +1,7 @@

{{ page.title }}

+ {%- if logged_on %}

Edit Page

{% endif %} {{ page.text }}
diff --git a/src/MyWebLog/themes/awftw/single-post.liquid b/src/MyWebLog/themes/awftw/single-post.liquid index b4c452d..93a69d8 100644 --- a/src/MyWebLog/themes/awftw/single-post.liquid +++ b/src/MyWebLog/themes/awftw/single-post.liquid @@ -5,6 +5,7 @@

{{ post.title }}

+ {%- if logged_on %}

Edit Post

{% endif %} {% assign media = post.metadata | value: "episode_media_file" %} {%- unless media == "-- episode_media_file not found --" %}
- {% comment %} - TODO: reading time? -
-

Reading Time

-
- - #[= readingTime(page.content, 'minutes', 175)] -
-
- {% endcomment %} {%- assign has_ot = false -%} {%- for ot_id in ot_books -%} {%- if post.category_ids contains ot_id %}{% assign has_ot = true %}{% endif -%} diff --git a/src/MyWebLog/wwwroot/themes/awftw/style.css b/src/MyWebLog/wwwroot/themes/awftw/style.css index 16ea553..b04f8e7 100644 --- a/src/MyWebLog/wwwroot/themes/awftw/style.css +++ b/src/MyWebLog/wwwroot/themes/awftw/style.css @@ -67,6 +67,9 @@ h1, h2, h3, h4, p, ul { margin-top: 0; margin-bottom: 1rem; } +sup { + vertical-align: text-top; +} .site-header { display: flex; flex-flow: row wrap; @@ -200,9 +203,10 @@ blockquote p:nth-last-of-type(2) { blockquote.standard p:nth-last-of-type(2) { margin-bottom: inherit; } -blockquote.standard { +blockquote.standard, blockquote blockquote { margin: 1rem 2rem 1rem 1rem; border-left: solid 3px var(--accent-color); + border-top: unset; font-family: inherit; } blockquote cite { @@ -225,7 +229,7 @@ blockquote cite::before { } blockquote sup { color: var(--superscript-color); - padding-right: .35rem; + padding-right: .25rem; } .lord, .sc { font-variant: small-caps; @@ -338,3 +342,8 @@ a.dl:link, a.dl:visited { color: var(--audio-text-color); } +@media all and (max-width: 40rem) { + blockquote { + margin: 2rem 0; + } +}