- Fix a few issues with podcast feed generation

- Tweak styles for devotional theme
- Fix bug with page cache building
This commit is contained in:
Daniel J. Summers 2022-06-04 20:49:14 -04:00
parent b367229814
commit 2394f03b3b
9 changed files with 68 additions and 38 deletions

View File

@ -312,10 +312,15 @@ module WebLog =
let _, leadPath = hostAndPath webLog let _, leadPath = hostAndPath webLog
$"{leadPath}/{Permalink.toString permalink}" $"{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 localTime webLog (date : DateTime) =
let tz = TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone TimeZoneInfo.ConvertTimeFromUtc
TimeZoneInfo.ConvertTimeFromUtc (DateTime (date.Ticks, DateTimeKind.Utc), tz) (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 /// A user of the web log

View File

@ -65,7 +65,10 @@ module PageListCache =
let update (ctx : HttpContext) = backgroundTask { let update (ctx : HttpContext) = backgroundTask {
let webLog = ctx.WebLog let webLog = ctx.WebLog
let! pages = Data.Page.findListed webLog.id ctx.Conn 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
} }

View File

@ -95,9 +95,18 @@ let private toFeedItem webLog (authors : MetaItem list) (cats : DisplayCategory[
Content = TextSyndicationContent.CreatePlaintextContent plainText) Content = TextSyndicationContent.CreatePlaintextContent plainText)
item.AddPermalink (Uri item.Id) item.AddPermalink (Uri item.Id)
let xmlDoc = XmlDocument ()
let encoded = let encoded =
post.text.Replace("src=\"/", $"src=\"{webLog.urlBase}/").Replace ("href=\"/", $"href=\"{webLog.urlBase}/") let txt =
item.ElementExtensions.Add ("encoded", Namespace.content, encoded) 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 ( item.Authors.Add (SyndicationPerson (
Name = (authors |> List.find (fun a -> a.name = WebLogUserId.toString post.authorId)).value)) Name = (authors |> List.find (fun a -> a.name = WebLogUserId.toString post.authorId)).value))
[ post.categoryIds [ post.categoryIds
@ -124,6 +133,7 @@ let private addEpisode webLog (feed : CustomFeed) (post : Post) (item : Syndicat
let epMediaUrl = let epMediaUrl =
match (meta >> Option.get >> value) "episode_media_file" with match (meta >> Option.get >> value) "episode_media_file" with
| link when link.StartsWith "http" -> link | link when link.StartsWith "http" -> link
| link when Option.isSome podcast.mediaBaseUrl -> $"{podcast.mediaBaseUrl.Value}{link}"
| link -> WebLog.absoluteUrl webLog (Permalink link) | link -> WebLog.absoluteUrl webLog (Permalink link)
let epMediaType = let epMediaType =
match meta "episode_media_type", podcast.defaultMediaType with 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 with :? ArgumentException -> ExplicitRating.toString podcast.explicit
let xmlDoc = XmlDocument () let xmlDoc = XmlDocument ()
let enclosure = xmlDoc.CreateElement "enclosure" let enclosure =
enclosure.SetAttribute ("url", epMediaUrl) let it = xmlDoc.CreateElement "enclosure"
meta "episode_media_length" |> Option.iter (fun it -> enclosure.SetAttribute ("length", it.value)) it.SetAttribute ("url", epMediaUrl)
epMediaType |> Option.iter (fun typ -> enclosure.SetAttribute ("type", typ)) 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 enclosure
item.ElementExtensions.Add image
item.ElementExtensions.Add ("creator", Namespace.dc, podcast.displayedAuthor) item.ElementExtensions.Add ("creator", Namespace.dc, podcast.displayedAuthor)
item.ElementExtensions.Add ("author", Namespace.iTunes, podcast.displayedAuthor) item.ElementExtensions.Add ("author", Namespace.iTunes, podcast.displayedAuthor)
item.ElementExtensions.Add ("summary", Namespace.iTunes, stripHtml post.text) item.ElementExtensions.Add ("summary", Namespace.iTunes, stripHtml post.text)
item.ElementExtensions.Add ("image", Namespace.iTunes, epImageUrl)
item.ElementExtensions.Add ("explicit", Namespace.iTunes, epExplicit) item.ElementExtensions.Add ("explicit", Namespace.iTunes, epExplicit)
meta "episode_subtitle" meta "episode_subtitle"
|> Option.iter (fun it -> item.ElementExtensions.Add ("subtitle", Namespace.iTunes, it.value)) |> 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 "link", feedUrl
] ]
|> List.fold (fun elt (name, value) -> addChild xmlDoc "" "" name value elt) (xmlDoc.CreateElement "image") |> 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 = let owner =
[ "name", podcast.displayedAuthor [ "name", podcast.displayedAuthor
"email", podcast.email "email", podcast.email
] ]
|> List.fold (fun elt (name, value) -> addChild xmlDoc Namespace.iTunes "itunes" name value elt) |> List.fold (fun elt (name, value) -> addChild xmlDoc Namespace.iTunes "itunes" name value elt)
(xmlDoc.CreateElement ("itunes", "owner", Namespace.iTunes)) (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 image
rssFeed.ElementExtensions.Add owner rssFeed.ElementExtensions.Add owner
rssFeed.ElementExtensions.Add categorization rssFeed.ElementExtensions.Add categorization
rssFeed.ElementExtensions.Add iTunesImage
rssFeed.ElementExtensions.Add rawVoice
rssFeed.ElementExtensions.Add ("summary", Namespace.iTunes, podcast.summary) rssFeed.ElementExtensions.Add ("summary", Namespace.iTunes, podcast.summary)
rssFeed.ElementExtensions.Add ("author", Namespace.iTunes, podcast.displayedAuthor) 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 ("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)) podcast.subtitle |> Option.iter (fun sub -> rssFeed.ElementExtensions.Add ("subtitle", Namespace.iTunes, sub))
/// Get the feed's self reference and non-feed link /// Get the feed's self reference and non-feed link
@ -241,9 +266,10 @@ let private selfAndLink webLog feedType =
| StandardFeed path -> path | StandardFeed path -> path
| CategoryFeed (_, path) -> path | CategoryFeed (_, path) -> path
| TagFeed (_, path) -> path | TagFeed (_, path) -> path
// TODO: get defined path for custom feed
| Custom (_, path) -> path | Custom (_, path) -> path
|> function |> 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 /// Set the title and description of the feed based on its source
let private setTitleAndDescription feedType (webLog : WebLog) (cats : DisplayCategory[]) (feed : SyndicationFeed) = 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 toItem post =
let item = toFeedItem webLog authors cats tagMaps post let item = toFeedItem webLog authors cats tagMaps post
match podcast with 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 addEpisode webLog feed post item
| Some _ -> | Some _ ->
warn "Feed" ctx $"[{webLog.name} {Permalink.toString self}] \"{stripHtml post.title}\" has no media" 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 addNamespace feed "content" Namespace.content
setTitleAndDescription feedType webLog cats feed setTitleAndDescription feedType webLog cats feed
feed.LastUpdatedTime <- DateTimeOffset <| (List.head posts).updatedOn feed.LastUpdatedTime <- (List.head posts).updatedOn |> DateTimeOffset
feed.Generator <- generator ctx feed.Generator <- generator ctx
feed.Items <- posts |> Seq.ofList |> Seq.map toItem feed.Items <- posts |> Seq.ofList |> Seq.map toItem
feed.Language <- "en" feed.Language <- "en"

View File

@ -336,10 +336,7 @@ let save : HttpHandler = fun next ctx -> task {
let post = let post =
match model.setPublished with match model.setPublished with
| true -> | true ->
let dt = let dt = WebLog.utcTime webLog model.pubOverride.Value
TimeZoneInfo.ConvertTimeToUtc
(DateTime (model.pubOverride.Value.Ticks, DateTimeKind.Unspecified),
TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone)
match model.setUpdated with match model.setUpdated with
| true -> | true ->
{ post with { post with

View File

@ -3,7 +3,7 @@
"hostname": "data02.bitbadger.solutions", "hostname": "data02.bitbadger.solutions",
"database": "myWebLog_dev" "database": "myWebLog_dev"
}, },
"Generator": "myWebLog 2.0-alpha30", "Generator": "myWebLog 2.0-alpha31",
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"MyWebLog.Handlers": "Debug" "MyWebLog.Handlers": "Debug"

View File

@ -19,10 +19,8 @@
</a> </a>
</h1> </h1>
<p class="item-meta"> <p class="item-meta">
<i class="fa fa-calendar" title="Date"></i> {{ post.published_on | date: "dddd, MMMM d, yyyy" }} &nbsp; <i class="fa fa-calendar" title="Date"></i> {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
{% comment %} TODO: reading time? {% if logged_on %} &bull; <a href="{{ post | edit_post_link }}">Edit Post</a>{% endif %}
#[i.fa.fa-clock-o(title='Clock' aria-hidden='true')] #[= readingTime(post.content, 'minutes', 175)]
{% endcomment %}
</p> </p>
{%- assign media = post.metadata | value: "episode_media_file" -%} {%- assign media = post.metadata | value: "episode_media_file" -%}
{%- unless media == "-- episode_media_file not found --" %} {%- unless media == "-- episode_media_file not found --" %}

View File

@ -1,6 +1,7 @@
<div class="content"> <div class="content">
<article class="item"> <article class="item">
<h1 class="item-heading">{{ page.title }}</h1> <h1 class="item-heading">{{ page.title }}</h1>
{%- if logged_on %}<p class="item-meta"><a href="{{ page | edit_page_link }}">Edit Page</a></p>{% endif %}
{{ page.text }} {{ page.text }}
</article> </article>
</div> </div>

View File

@ -5,6 +5,7 @@
<div class="content"> <div class="content">
<article class="item"> <article class="item">
<h1 class="item-heading">{{ post.title }}</h1> <h1 class="item-heading">{{ post.title }}</h1>
{%- if logged_on %}<p class="item-meta"><a href="{{ post | edit_post_link }}">Edit Post</a></p>{% endif %}
{% assign media = post.metadata | value: "episode_media_file" %} {% assign media = post.metadata | value: "episode_media_file" %}
{%- unless media == "-- episode_media_file not found --" %} {%- unless media == "-- episode_media_file not found --" %}
<aside class="podcast"> <aside class="podcast">
@ -44,16 +45,6 @@
{{ post.published_on | date: "dddd, MMMM d, yyyy" }} {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
</div> </div>
</div> </div>
{% comment %}
TODO: reading time?
<div class="item">
<h4 class="item-heading">Reading Time</h4>
<div class="text-center">
<i class="fa fa-clock-o" title="Clock" aria-hidden="true"></i>
#[= readingTime(page.content, 'minutes', 175)]
</div>
</div>
{% endcomment %}
{%- assign has_ot = false -%} {%- assign has_ot = false -%}
{%- for ot_id in ot_books -%} {%- for ot_id in ot_books -%}
{%- if post.category_ids contains ot_id %}{% assign has_ot = true %}{% endif -%} {%- if post.category_ids contains ot_id %}{% assign has_ot = true %}{% endif -%}

View File

@ -67,6 +67,9 @@ h1, h2, h3, h4, p, ul {
margin-top: 0; margin-top: 0;
margin-bottom: 1rem; margin-bottom: 1rem;
} }
sup {
vertical-align: text-top;
}
.site-header { .site-header {
display: flex; display: flex;
flex-flow: row wrap; flex-flow: row wrap;
@ -200,9 +203,10 @@ blockquote p:nth-last-of-type(2) {
blockquote.standard p:nth-last-of-type(2) { blockquote.standard p:nth-last-of-type(2) {
margin-bottom: inherit; margin-bottom: inherit;
} }
blockquote.standard { blockquote.standard, blockquote blockquote {
margin: 1rem 2rem 1rem 1rem; margin: 1rem 2rem 1rem 1rem;
border-left: solid 3px var(--accent-color); border-left: solid 3px var(--accent-color);
border-top: unset;
font-family: inherit; font-family: inherit;
} }
blockquote cite { blockquote cite {
@ -225,7 +229,7 @@ blockquote cite::before {
} }
blockquote sup { blockquote sup {
color: var(--superscript-color); color: var(--superscript-color);
padding-right: .35rem; padding-right: .25rem;
} }
.lord, .sc { .lord, .sc {
font-variant: small-caps; font-variant: small-caps;
@ -338,3 +342,8 @@ a.dl:link,
a.dl:visited { a.dl:visited {
color: var(--audio-text-color); color: var(--audio-text-color);
} }
@media all and (max-width: 40rem) {
blockquote {
margin: 2rem 0;
}
}