Skip to content

Commit 638f75e

Browse files
committed
Allow publishing category feeds
In some cases, one needs to have custom feeds pertaining to a particular topic (such as for planet aggregations) and thus having category feeds is useful. This adds `category_feeds` and `category_feeds_dir` config options
1 parent dc41368 commit 638f75e

File tree

5 files changed

+112
-50
lines changed

5 files changed

+112
-50
lines changed

docs/configuration.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,18 @@ Will result in:
426426

427427
Default: `None`.
428428

429+
### Category feeds
430+
431+
Enables generating separate feeds for each category.
432+
433+
Default: `false`.
434+
435+
### Category feeds directory
436+
437+
Directory to put category feeds into
438+
439+
Default: `rss_dir`.
440+
429441
----
430442

431443
## Integration

docs/schema.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,18 @@
127127
"markdownDescription": "https://guts.github.io/mkdocs-rss-plugin/configuration/#url-parameters",
128128
"type": "object",
129129
"default": null
130+
},
131+
"category_feeds": {
132+
"title": "Separate feeds for each category",
133+
"markdownDescription": "https://guts.github.io/mkdocs-rss-plugin/configuration/#category_feeds",
134+
"type": "boolean",
135+
"default": false
136+
},
137+
"category_feeds_dir": {
138+
"title": "Directory to put category feeds into",
139+
"markdownDescription": "https://guts.github.io/mkdocs-rss-plugin/configuration/#category_feeds_directory",
140+
"type": "string",
141+
"default": "rss"
130142
}
131143
},
132144
"additionalProperties": false

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ plugins:
3232
utm_source: "documentation"
3333
utm_medium: "RSS"
3434
utm_campaign: "feed-syndication"
35+
category_feeds: false
36+
category_feeds_dir: rss
3537
- search
3638

3739
theme:

mkdocs_rss_plugin/plugin.py

Lines changed: 82 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
# ########## Libraries #############
55
# ##################################
66

7-
# standard library
87
import logging
8+
9+
# standard library
10+
import os
911
from copy import deepcopy
1012
from datetime import datetime
1113
from 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)

tests/test_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def test_plugin_config_defaults(self):
6868
"pretty_print": False,
6969
"match_path": ".*",
7070
"url_parameters": None,
71+
"category_feeds": False,
72+
"category_feeds_dir": "rss",
7173
}
7274

7375
# load
@@ -92,6 +94,8 @@ def test_plugin_config_image(self):
9294
"pretty_print": False,
9395
"match_path": ".*",
9496
"url_parameters": None,
97+
"category_feeds": False,
98+
"category_feeds_dir": "rss",
9599
}
96100

97101
# custom config

0 commit comments

Comments
 (0)