136 lines
4.7 KiB
Python
136 lines
4.7 KiB
Python
import rfeed
|
|
from datetime import datetime
|
|
|
|
|
|
from .common import SiteConfig
|
|
from .articles import ArticleMetadata, Article, format_article_tags
|
|
from .templating import format_html_template, TemplateSelections
|
|
|
|
|
|
def build_tag_index(index: dict[str, Article], wildcard ='*') -> dict[str, list[Article]]:
|
|
'''Creates an inverted index mapping each article tag to a postings list of articles
|
|
with said tag.'''
|
|
tag_index = {}
|
|
|
|
# Index the articles in ascending order of original publication date.
|
|
for article in sorted(index.values(), key = lambda a: a.metadata.date):
|
|
|
|
# Add all articles to the wildcard tag's postings list.
|
|
if wildcard is not None:
|
|
tag_index[wildcard] = (tag_index.get(wildcard,[])) + [article]
|
|
|
|
# Add the article to each of its tags' posting lists.
|
|
for tag in article.metadata.tags:
|
|
tag_index[tag] = (tag_index.get(tag,[])) + [article]
|
|
|
|
return tag_index
|
|
|
|
|
|
def build_blog_archive(
|
|
site: SiteConfig,
|
|
index: dict[str, Article],
|
|
template_selections: TemplateSelections,
|
|
**kwargs
|
|
) -> str:
|
|
'''Converts an index, formatted as filestem: (metadata, contents) dict,
|
|
into an HTML page containing the list of articles, sorted from newest to oldest.
|
|
|
|
Note: partials must be expanded into the kwargs, as they are needed to generate
|
|
the overall page.
|
|
'''
|
|
|
|
# Add each article as a list item to an unordered list.
|
|
archive_html_list = '<ul>'
|
|
for article in sorted(index.values(), key = lambda a: a.metadata.date)[::-1]:
|
|
|
|
# Generate HTML for the article (including metadata tags).
|
|
archive_html_list += format_html_template(
|
|
template_selections['archive_li'],
|
|
article_filestem = article,
|
|
blog_tags = ' '.join(format_article_tags(article.metadata.tags, template_selections['tag'], site = site)),
|
|
article = article,
|
|
site = site,
|
|
**kwargs
|
|
)
|
|
archive_html_list +='</ul>'
|
|
|
|
tag_index = build_tag_index(index)
|
|
|
|
tag_selector_options = []
|
|
tag_selector_css_rules = [f'''
|
|
body:has(input[name="tag-selector"][value="*"]:checked) li:has(.blog-tag){{
|
|
display: list-item!important;
|
|
}}
|
|
''']
|
|
|
|
# Add tag selector options in descending order of article count.
|
|
for tag, articles in sorted(tag_index.items(), key = lambda item : -len(item[1])):
|
|
tag_selector_options.append(format_html_template(
|
|
template_selections['tag_selector_option'],
|
|
tag_name = tag,
|
|
number_with_tag = len(articles),
|
|
site = site,
|
|
**kwargs
|
|
))
|
|
if tag == '*':
|
|
continue
|
|
tag_selector_css_rules.append(f'''
|
|
body:has(input[name="tag-selector"]:not([value="{tag}"]):checked) li:has(.blog-tag[data="{tag}"]){{
|
|
display: none;
|
|
}}
|
|
body:has(input[name="tag-selector"][value="{tag}"]:checked) li:has(.blog-tag[data="{tag}"]){{
|
|
display: list-item!important;
|
|
}}
|
|
''')
|
|
|
|
# For Python 3.9-friendliness.
|
|
newline = '\n'
|
|
|
|
# Generate the archive article.
|
|
archive_html_article = format_html_template(
|
|
template_selections['archive_article'],
|
|
content = archive_html_list,
|
|
tag_selector_options = ' '.join(tag_selector_options),
|
|
tag_selector_css_rules = f'<style>{newline.join(tag_selector_css_rules)}</style>',
|
|
site = site,
|
|
**kwargs
|
|
)
|
|
|
|
# Interpolate the article into the overall page template.
|
|
archive_html_page = format_html_template(
|
|
template_selections['page'],
|
|
content = archive_html_article,
|
|
site = site,
|
|
**kwargs
|
|
)
|
|
|
|
with open(f"{site.web_root.rstrip('/')}/archive.html", 'w') as f:
|
|
f.write(archive_html_page)
|
|
|
|
|
|
def build_rss_feed(site: SiteConfig, index: dict[str, Article]):
|
|
feed = rfeed.Feed(
|
|
title = site.title,
|
|
link = f"{site.base_url.rstrip('/')}/rss.xml",
|
|
description = site.description,
|
|
language = "en-US",
|
|
lastBuildDate = datetime.now(),
|
|
items = [
|
|
rfeed.Item(
|
|
title = article.metadata.title,
|
|
link = f"{site.base_url.rstrip('/')}/{article.path}",
|
|
description = article.metadata.description,
|
|
author = article.metadata.author,
|
|
guid = rfeed.Guid(article.path),
|
|
pubDate = datetime(
|
|
article.metadata.date.year,
|
|
article.metadata.date.month,
|
|
article.metadata.date.day
|
|
)
|
|
)
|
|
for article in index.values()
|
|
]
|
|
)
|
|
|
|
with open(f"{site.web_root.rstrip('/')}/rss.xml", 'w') as f:
|
|
f.write(feed.rss()) |