@@ -110,7 +110,13 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig:
110110 return config
111111
112112 # Fail if any export option is enabled
113- if not any ([self .config .json_feed_enabled , self .config .rss_feed_enabled ]):
113+ if not any (
114+ [
115+ self .config .atom_feed_enabled ,
116+ self .config .json_feed_enabled ,
117+ self .config .rss_feed_enabled ,
118+ ]
119+ ):
114120 logger .error (
115121 "At least one export option has to be enabled. Plugin is disabled."
116122 )
@@ -237,18 +243,24 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig:
237243 # final feed url
238244 if base_feed .html_url :
239245 # concatenate both URLs
240- self .feed_created .rss_url = (
241- base_feed .html_url + self .config .feeds_filenames .rss_created
246+ self .feed_created .atom_url = (
247+ base_feed .html_url + self .config .feeds_filenames .atom_created
242248 )
243- self .feed_updated .rss_url = (
244- base_feed .html_url + self .config .feeds_filenames .rss_updated
249+ self .feed_updated .atom_url = (
250+ base_feed .html_url + self .config .feeds_filenames .atom_updated
245251 )
246252 self .feed_created .json_url = (
247253 base_feed .html_url + self .config .feeds_filenames .json_created
248254 )
249255 self .feed_updated .json_url = (
250256 base_feed .html_url + self .config .feeds_filenames .json_updated
251257 )
258+ self .feed_created .rss_url = (
259+ base_feed .html_url + self .config .feeds_filenames .rss_created
260+ )
261+ self .feed_updated .rss_url = (
262+ base_feed .html_url + self .config .feeds_filenames .rss_updated
263+ )
252264 else :
253265 logger .error (
254266 "The variable `site_url` is not set in the MkDocs "
@@ -257,7 +269,9 @@ def on_config(self, config: MkDocsConfig) -> MkDocsConfig:
257269 )
258270 self .feed_created .rss_url = self .feed_updated .json_url = (
259271 self .feed_updated .rss_url
260- ) = self .feed_updated .json_url = None
272+ ) = self .feed_updated .json_url = self .feed_created .atom_url = (
273+ self .feed_updated .atom_url
274+ ) = None
261275
262276 # ending event
263277 return config
@@ -323,6 +337,11 @@ def on_page_content(
323337 else :
324338 page_url_comments = None
325339
340+ # Store full HTML content if needed for Atom feed
341+ page_content : str | None = None
342+ if self .config .abstract_chars_count == - 1 :
343+ page_content = html
344+
326345 # append to list to be filtered later
327346 self .pages_to_filter .append (
328347 PageInformation (
@@ -332,6 +351,7 @@ def on_page_content(
332351 in_page = page , categories_labels = self .config .categories
333352 ),
334353 comments_url = page_url_comments ,
354+ html_content = page_content ,
335355 created = page_dates [0 ],
336356 description = self .util .get_description_or_abstract (
337357 in_page = page ,
@@ -362,13 +382,13 @@ def on_post_build(self, config: config_options.Config) -> None:
362382 return
363383
364384 # pretty print or not
365- pretty_print = self .config .pretty_print
385+ pretty_print : bool = self .config .pretty_print
366386
367387 # output filepaths
368- out_feed_created = Path (config .site_dir ).joinpath (
388+ out_rss_created = Path (config .site_dir ).joinpath (
369389 self .config .feeds_filenames .rss_created
370390 )
371- out_feed_updated = Path (config .site_dir ).joinpath (
391+ out_rss_updated = Path (config .site_dir ).joinpath (
372392 self .config .feeds_filenames .rss_updated
373393 )
374394 out_json_created = Path (config .site_dir ).joinpath (
@@ -377,6 +397,12 @@ def on_post_build(self, config: config_options.Config) -> None:
377397 out_json_updated = Path (config .site_dir ).joinpath (
378398 self .config .feeds_filenames .json_updated
379399 )
400+ out_atom_created : Path = Path (config .site_dir ).joinpath (
401+ self .config .feeds_filenames .atom_created
402+ )
403+ out_atom_updated : Path = Path (config .site_dir ).joinpath (
404+ self .config .feeds_filenames .atom_updated
405+ )
380406
381407 # created items
382408 self .feed_created .entries .extend (
@@ -435,7 +461,7 @@ def on_post_build(self, config: config_options.Config) -> None:
435461 page .pub_date = format_datetime (dt = page .created )
436462
437463 # write file
438- with out_feed_created .open (mode = "w" , encoding = "UTF8" ) as fifeed_created :
464+ with out_rss_created .open (mode = "w" , encoding = "UTF8" ) as fifeed_created :
439465 if pretty_print :
440466 fifeed_created .write (template .render (feed = self .feed_created ))
441467 else :
@@ -457,7 +483,7 @@ def on_post_build(self, config: config_options.Config) -> None:
457483 page .pub_date = format_datetime (dt = page .updated )
458484
459485 # write file
460- with out_feed_updated .open (mode = "w" , encoding = "UTF8" ) as fifeed_updated :
486+ with out_rss_updated .open (mode = "w" , encoding = "UTF8" ) as fifeed_updated :
461487 if pretty_print :
462488 fifeed_updated .write (template .render (feed = self .feed_updated ))
463489 else :
@@ -487,3 +513,88 @@ def on_post_build(self, config: config_options.Config) -> None:
487513 fp ,
488514 indent = 4 if self .config .pretty_print else None ,
489515 )
516+
517+ # ATOM FEED
518+ if self .config .atom_feed_enabled :
519+ # Jinja environment depending on the pretty print option
520+ if pretty_print :
521+ env = Environment (
522+ autoescape = select_autoescape (["html" , "xml" ]),
523+ loader = FileSystemLoader (self .tpl_folder ),
524+ )
525+ else :
526+ env = Environment (
527+ autoescape = select_autoescape (["html" , "xml" ]),
528+ loader = FileSystemLoader (self .tpl_folder ),
529+ lstrip_blocks = True ,
530+ trim_blocks = True ,
531+ )
532+
533+ template = env .get_template ("atom.xml.jinja2" )
534+
535+ # -- Feed sorted by creation date
536+ logger .debug (
537+ "Fill creation dates and dump created feed into Atom template."
538+ )
539+
540+ # Format dates for Atom (ISO 8601)
541+ for page in self .feed_created .entries :
542+ page .atom_published = page .created .isoformat ()
543+ page .atom_updated = page .updated .isoformat ()
544+
545+ # Format feed buildDate for Atom (ISO 8601)
546+ build_date_atom : str = datetime .fromtimestamp (
547+ get_build_timestamp ()
548+ ).isoformat ()
549+
550+ # Temporarily store the ISO format
551+ original_build_date : str = self .feed_created .buildDate
552+ self .feed_created .buildDate = build_date_atom
553+
554+ # write file
555+ with out_atom_created .open (mode = "w" , encoding = "UTF8" ) as fiatom_created :
556+ if pretty_print :
557+ fiatom_created .write (template .render (feed = self .feed_created ))
558+ else :
559+ prev_char = ""
560+ for char in template .render (feed = asdict (self .feed_created )):
561+ if char == "\n " :
562+ # convert new lines to spaces to preserve sentence structure
563+ char = " "
564+ if char == " " and prev_char == " " :
565+ prev_char = char
566+ continue
567+ prev_char = char
568+ fiatom_created .write (char )
569+
570+ # Restore original buildDate
571+ self .feed_created .buildDate = original_build_date
572+
573+ # -- Feed sorted by update date
574+ logger .debug ("Fill update dates and dump updated feed into Atom template." )
575+
576+ for page in self .feed_updated .entries :
577+ page .atom_published = page .created .isoformat ()
578+ page .atom_updated = page .updated .isoformat ()
579+
580+ original_build_date = self .feed_updated .buildDate
581+ self .feed_updated .buildDate = build_date_atom
582+
583+ # write file
584+ with out_atom_updated .open (mode = "w" , encoding = "UTF8" ) as fiatom_updated :
585+ if pretty_print :
586+ fiatom_updated .write (template .render (feed = self .feed_updated ))
587+ else :
588+ prev_char = ""
589+ for char in template .render (feed = asdict (self .feed_updated )):
590+ if char == "\n " :
591+ # convert new lines to spaces to preserve sentence structure
592+ char = " "
593+ if char == " " and prev_char == " " :
594+ prev_char = char
595+ continue
596+ prev_char = char
597+ fiatom_updated .write (char )
598+
599+ # Restore original buildDate
600+ self .feed_updated .buildDate = original_build_date
0 commit comments