44# ########## Libraries #############
55# ##################################
66
7- # standard library
87import logging
8+
9+ # standard library
10+ import os
911from copy import deepcopy
1012from datetime import datetime
1113from email .utils import formatdate
@@ -58,6 +60,8 @@ class GitRssPlugin(BasePlugin):
5860 ("match_path" , config_options .Type (str , default = ".*" )),
5961 ("pretty_print" , config_options .Type (bool , default = False )),
6062 ("url_parameters" , config_options .Type (dict , default = None )),
63+ ("category_feeds" , config_options .Type (bool , default = False )),
64+ ("category_feeds_dir" , config_options .Type (str , default = "rss" )),
6165 )
6266
6367 def __init__ (self ):
@@ -71,9 +75,13 @@ def __init__(self):
7175 self .meta_default_time = None
7276 # pages storage
7377 self .pages_to_filter = []
78+ # config
79+ self .category_feeds = False
80+ self .category_feeds_dir = "rss"
7481 # prepare output feeds
7582 self .feed_created = dict
7683 self .feed_updated = dict
84+ self .category_feed = dict
7785
7886 def on_config (self , config : config_options .Config ) -> dict :
7987 """The config event is the first event called on build and
@@ -123,6 +131,9 @@ def on_config(self, config: config_options.Config) -> dict:
123131 # pattern to match pages included in output
124132 self .match_path_pattern = compile (self .config .get ("match_path" ))
125133
134+ self .category_feeds = self .config .get ("category_feeds" )
135+ self .category_feeds_dir = self .config .get ("category_feeds_dir" )
136+
126137 # date handling
127138 if self .config .get ("date_from_meta" ) is not None :
128139 self .src_date_created = self .config .get ("date_from_meta" ).get (
@@ -162,6 +173,7 @@ def on_config(self, config: config_options.Config) -> dict:
162173 # create 2 final dicts
163174 self .feed_created = deepcopy (base_feed )
164175 self .feed_updated = deepcopy (base_feed )
176+ self .category_feed = deepcopy (base_feed )
165177
166178 # final feed url
167179 if base_feed .get ("html_url" ):
@@ -272,6 +284,41 @@ def on_page_content(
272284 )
273285 )
274286
287+ def render_feed (self , pretty_print : bool , feed_name : str , feed : dict ):
288+ if pretty_print :
289+ # load Jinja environment and template
290+ env = Environment (
291+ autoescape = select_autoescape (["html" , "xml" ]),
292+ loader = FileSystemLoader (self .tpl_folder ),
293+ )
294+
295+ template = env .get_template (self .tpl_file .name )
296+
297+ # write feed to file
298+ with feed_name .open (mode = "w" , encoding = "UTF8" ) as fifeed :
299+ fifeed .write (template .render (feed = feed ))
300+ else :
301+ # load Jinja environment and template
302+ env = Environment (
303+ autoescape = select_autoescape (["html" , "xml" ]),
304+ loader = FileSystemLoader (self .tpl_folder ),
305+ lstrip_blocks = True ,
306+ trim_blocks = True ,
307+ )
308+ template = env .get_template (self .tpl_file .name )
309+
310+ # write feed to file stripping out spaces and new lines
311+ with feed_name .open (mode = "w" , encoding = "UTF8" ) as fifeed :
312+ prev_char = ""
313+ for char in template .render (feed = feed ):
314+ if char == "\n " :
315+ continue
316+ if char == " " and prev_char == " " :
317+ prev_char = char
318+ continue
319+ prev_char = char
320+ fifeed .write (char )
321+
275322 def on_post_build (self , config : config_options .Config ) -> dict :
276323 """The post_build event does not alter any variables. \
277324 Use this event to call post-build scripts. \
@@ -312,52 +359,37 @@ def on_post_build(self, config: config_options.Config) -> dict:
312359 )
313360 )
314361
315- # write feeds according to the pretty print option
316- if pretty_print :
317- # load Jinja environment and template
318- env = Environment (
319- autoescape = select_autoescape (["html" , "xml" ]),
320- loader = FileSystemLoader (self .tpl_folder ),
321- )
322-
323- template = env .get_template (self .tpl_file .name )
324-
325- # write feeds to files
326- with out_feed_created .open (mode = "w" , encoding = "UTF8" ) as fifeed_created :
327- fifeed_created .write (template .render (feed = self .feed_created ))
328-
329- with out_feed_updated .open (mode = "w" , encoding = "UTF8" ) as fifeed_updated :
330- fifeed_updated .write (template .render (feed = self .feed_updated ))
331-
332- else :
333- # load Jinja environment and template
334- env = Environment (
335- autoescape = select_autoescape (["html" , "xml" ]),
336- loader = FileSystemLoader (self .tpl_folder ),
337- lstrip_blocks = True ,
338- trim_blocks = True ,
339- )
340- template = env .get_template (self .tpl_file .name )
341-
342- # write feeds to files stripping out spaces and new lines
343- with out_feed_created .open (mode = "w" , encoding = "UTF8" ) as fifeed_created :
344- prev_char = ""
345- for char in template .render (feed = self .feed_created ):
346- if char == "\n " :
347- continue
348- if char == " " and prev_char == " " :
349- prev_char = char
350- continue
351- prev_char = char
352- fifeed_created .write (char )
353-
354- with out_feed_updated .open (mode = "w" , encoding = "UTF8" ) as fifeed_updated :
355- for char in template .render (feed = self .feed_updated ):
356- if char == "\n " :
357- prev_char = char
358- continue
359- if char == " " and prev_char == " " :
360- prev_char = char
361- continue
362- prev_char = char
363- fifeed_updated .write (char )
362+ # Render main feeds
363+ self .render_feed (pretty_print , out_feed_created , self .feed_created )
364+ self .render_feed (pretty_print , out_feed_updated , self .feed_updated )
365+
366+ # Render category feeds if enabled
367+ if self .category_feeds :
368+ feeds = {}
369+ # collect feeds of pages per category
370+ for page in self .pages_to_filter :
371+ for category in page .categories :
372+ feeds .setdefault (category , []).append (page )
373+
374+ # Ensure target directory exists
375+ path = Path (config .get ("site_dir" )) / self .category_feeds_dir
376+ os .makedirs (path , exist_ok = True )
377+
378+ for category , pages in feeds .items ():
379+ # Create a feed per category
380+ filename = f"{ category } .xml"
381+ feed = deepcopy (self .category_feed )
382+ feed ["rss_url" ] = (
383+ self .category_feed .get ("html_url" )
384+ + self .category_feeds_dir
385+ + "/"
386+ + filename
387+ )
388+ feed .get ("entries" ).extend (
389+ self .util .filter_pages (
390+ pages = pages ,
391+ length = self .config .get ("length" , 20 ),
392+ attribute = "created" ,
393+ )
394+ )
395+ self .render_feed (pretty_print , path / filename , feed )
0 commit comments