- Fix a few issues with podcast feed generation
- Tweak styles for devotional theme - Fix bug with page cache building
This commit is contained in:
parent
b367229814
commit
2394f03b3b
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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" }}
|
<i class="fa fa-calendar" title="Date"></i> {{ post.published_on | date: "dddd, MMMM d, yyyy" }}
|
||||||
{% comment %} TODO: reading time?
|
{% if logged_on %} • <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 --" %}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 -%}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user