- 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)) | ||||||
|     item.ElementExtensions.Add enclosure |         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 ("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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user