Skip to content

Commit

Permalink
Merge pull request #14 from Guts/feature/date-published
Browse files Browse the repository at this point in the history
Feature: override date from git log using meta from yaml-frontmatter
  • Loading branch information
Guts authored Dec 24, 2020
2 parents cf13da6 + b758e11 commit 18066e2
Show file tree
Hide file tree
Showing 10 changed files with 205 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ exclude: "node_modules|migrations|.venv|tests/dev/|tests/fixtures/"
fail_fast: false
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.3.0
rev: v3.4.0
hooks:
- id: check-added-large-files
args: ['--maxkb=500']
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,21 @@ A plugin for [MkDocs](https://www.mkdocs.org), the static site generator, which

## Usage

Typical `mkdocs.yml`:

```yaml
plugins:
- rss:
abstract_chars_count: 160
feed_ttl: 1440
length: 20
date_from_meta:
as_creation: "date"
as_update: false
datetime_format: "%Y-%m-%d %H:%M"
image: https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Feed-icon.svg/128px-Feed-icon.svg.png
```
For further information, [see the user documentation](https://guts.github.io/mkdocs-rss-plugin/).
## Development
Expand Down
17 changes: 16 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,29 @@
# a list of builtin themes.
#
html_theme = "sphinx_rtd_theme"
html_theme_options = {
# "canonical_url": __about__.__uri_homepage__,
"display_version": True,
"logo_only": False,
"prev_next_buttons_location": "both",
"style_external_links": True,
"style_nav_header_background": "SteelBlue",
# Toc options
"collapse_navigation": False,
"includehidden": False,
"navigation_depth": 4,
"sticky_navigation": False,
"titles_only": False,
}

html_sidebars = {
"**": ["globaltoc.html", "relations.html", "sourcelink.html", "searchbox.html"]
}

# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ["_static"]
# html_static_path = ["_static"]

# Configuration for intersphinx (refer to others docs).
intersphinx_mapping = {
Expand Down
55 changes: 54 additions & 1 deletion docs/usage/configuration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
title: Configuration
date: 2020-12-31 14:20
description: Configuration steps and settings for MkDocs RSS plugin
image: "https://svgsilh.com/png-512/97849.png"
---
Expand Down Expand Up @@ -100,14 +101,63 @@ Output:

### Item description length

To fill each [item description element](https://www.w3schools.com/xml/rss_tag_title_link_description_item.asp), the plugin first tries to retrieve the value of the keyword `description` from the [page metadata](https://python-markdown.github.io/extensions/meta_data/).
To fill each [item description element](https://www.w3schools.com/xml/rss_tag_title_link_description_item.asp), the plugin first tries to retrieve the value of the keyword `description` from the [page metadata].

If the page has no meta, then the plugin retrieves the first number of characters of the page content defined by this setting. Retrieved content is raw markdown.

`abstract_chars_count`: number of characters to use as item description.

Default: `150`

### Dates overriding

Basically, the plugin aims to retrieve creation and update dates from git log. But sometimes, it does not match the content workflow: markdown generated from sources, .

So, it's possible to use the dates manually specified into the [page metadata] through the [YAML frontmatter](https://www.mkdocs.org/user-guide/writing-your-docs/#meta-data).

- `as_creation`: meta tag name to use as creation date. Default to False.
- `as_update`: meta tag name to use as update date. Default to False.
- `datetime_format`: datetime format. Default to "%Y-%m-%d %H:%M".

#### Example

For example, in your `best_article.md` created in 2019, you can write the front-matter like this:

```markdown
---
title: "This page title is a perfect clickbait!"
authors: ["Julien M."]
date: "2020-10-22 17:18"
---
# This plugin will change your MkDocs life
Lorem ipsum [...]
```

So in your `mkdocs.yml` you will have:

```yaml
plugins:
- rss:
date_from_meta:
as_creation: "date"
as_update: false
datetime_format: "%Y-%m-%d %H:%M"
```

At the end, into the RSS you will get:

```xml
<item>
<title>This page title is a perfect clickbait!</title>
<link>https://website.com/articles/best_article/</link>
<pubDate>Thu, 22 Oct 2020 17:18:00 -0000</pubDate>
[...]
</item>
```

----

## Integration
Expand All @@ -125,3 +175,6 @@ To facilitate the discovery of RSS feeds, it's recomended to add relevant meta-t
<link rel="alternate" type="application/rss+xml" title="RSS feed of updated content" href="/feed_rss_updated.xml">
{% endblock %}
```

<!-- Hyperinks references -->
[page metadata]: https://python-markdown.github.io/extensions/meta_data/
4 changes: 4 additions & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ plugins:
- minify:
minify_html: true
- rss:
date_from_meta:
as_creation: "date"
as_update: false
datetime_format: "%Y-%m-%d %H:%M"
image: https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Feed-icon.svg/128px-Feed-icon.svg.png
- search

Expand Down
4 changes: 1 addition & 3 deletions mkdocs_rss_plugin/__about__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
"__author__",
"__copyright__",
"__email__",
"__executable_name__",
"__license__",
"__summary__",
"__title__",
Expand All @@ -33,9 +32,8 @@
__author__ = "Julien Moura"
__copyright__ = "2020 - {0}, {1}".format(date.today().year, __author__)
__email__ = "[email protected]"
__executable_name__ = "MkDocsRssPlugin.exe"
__license__ = "GNU General Public License v3.0"
__summary__ = "Generates a static RSS feed using git log."
__summary__ = "MkDocs plugin which generates a static RSS feed using git log."
__title__ = "MkDocs RSS plugin"
__title_clean__ = "".join(e for e in __title__ if e.isalnum())
__uri__ = "https://github.com/Guts/mkdocs-rss-plugin/"
Expand Down
35 changes: 33 additions & 2 deletions mkdocs_rss_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,19 @@
OUTPUT_FEED_CREATED = "feed_rss_created.xml"
OUTPUT_FEED_UPDATED = "feed_rss_updated.xml"

logger = logging.getLogger("mkdocs.mkdocs_rss_plugin")


# ############################################################################
# ########## Classes ###############
# ##################################


class GitRssPlugin(BasePlugin):
config_scheme = (
("abstract_chars_count", config_options.Type(int, default=150)),
("abstract_chars_count", config_options.Type(int, default=160)),
("category", config_options.Type(str, default=None)),
("date_from_meta", config_options.Type(dict, default=None)),
("feed_ttl", config_options.Type(int, default=1440)),
("image", config_options.Type(str, default=None)),
("length", config_options.Type(int, default=20)),
Expand All @@ -48,6 +53,9 @@ class GitRssPlugin(BasePlugin):
def __init__(self):
# tooling
self.util = Util()
# dates source
self.src_date_created = self.src_date_updated = "git"
self.meta_datetime_format = None
# pages storage
self.pages_to_filter = []
# prepare output feeds
Expand Down Expand Up @@ -95,6 +103,24 @@ def on_config(self, config: config_options.Config) -> dict:
if self.config.get("image"):
base_feed["logo_url"] = self.config.get("image")

# date handling
if self.config.get("date_from_meta") is not None:
self.src_date_created = self.config.get("date_from_meta").get(
"as_creation", False
)
self.src_date_updated = self.config.get("date_from_meta").get(
"as_update", False
)
self.meta_datetime_format = self.config.get("date_from_meta").get(
"datetime_format", "%Y-%m-%d %H:%M"
)
logger.debug(
"[rss-plugin] Dates will be retrieved from page meta (yaml "
"frontmatter). The git log will be used as fallback."
)
else:
logger.debug("[rss-plugin] Dates will be retrieved from git log.")

# create 2 final dicts
self.feed_created = deepcopy(base_feed)
self.feed_updated = deepcopy(base_feed)
Expand Down Expand Up @@ -139,7 +165,12 @@ def on_page_markdown(
str: Markdown source text of page as string
"""
# retrieve dates from git log
page_dates = self.util.get_file_dates(path=page.file.abs_src_path)
page_dates = self.util.get_file_dates(
in_page=page,
source_date_creation=self.src_date_created,
source_date_update=self.src_date_updated,
meta_datetime_format=self.meta_datetime_format,
)

# append to list to be filtered later
self.pages_to_filter.append(
Expand Down
5 changes: 4 additions & 1 deletion mkdocs_rss_plugin/templates/rss.xml.jinja2
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0"
xmlns:atom="https://www.w3.org/2005/Atom"
xmlns:dc="https://purl.org/dc/elements/1.1/">
xmlns:dc="https://purl.org/dc/elements/1.1/"
xmlns:webfeeds=”http://webfeeds.org/rss/1.0″
>

<channel>
<!-- Mandatory elements -->
{% if feed.title is not none %}<title>{{ feed.title|e }}</title>{% endif %}
Expand Down
89 changes: 73 additions & 16 deletions mkdocs_rss_plugin/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

# standard library
import logging
from datetime import datetime
import ssl
from email.utils import formatdate
from mimetypes import guess_type
Expand Down Expand Up @@ -35,6 +36,13 @@
}


# ############################################################################
# ########## Globals ###############
# ##################################

logger = logging.getLogger("mkdocs.mkdocs_rss_plugin")


# ############################################################################
# ########## Classes #############
# ################################
Expand Down Expand Up @@ -83,34 +91,80 @@ def build_url(self, base_url: str, path: str, args_dict: dict = None) -> str:
url_parts[4] = urlencode(args_dict)
return urlunparse(url_parts)

def get_file_dates(self, path: str) -> Tuple[int, int]:
def get_file_dates(
self,
in_page: Page,
source_date_creation: str = "git",
source_date_update: str = "git",
meta_datetime_format: str = "%Y-%m-%d %H:%M",
) -> Tuple[int, int]:
"""Extract creation and update dates from git log for given file.
:param str path: path to a tracked file
:return: (creation date, last commit date)
:rtype: tuple of timestamps
:param in_page: input page to work with
:type in_page: Page
:param source_date_creation: which source to use (git or meta tag) for creation \
date, defaults to "git"
:type source_date_creation: str, optional
:param source_date_update: which source to use (git or meta tag) for update \
date, defaults to "git"
:type source_date_update: str, optional
:param meta_datetime_format: datetime string format, defaults to "%Y-%m-%d %H:%M"
:type meta_datetime_format: str, optional
:return: tuple of timestamps (creation date, last commit date)
:rtype: Tuple[int, int]
"""
# empty vars
dt_created = dt_updated = None

# explore git log
if self.git_is_valid:
# if enabled, try to retrieve dates from page metadata
if source_date_creation != "git" and in_page.meta.get(source_date_creation):
try:
dt_created = self.repo.log(
path, n=1, date="short", format="%at", diff_filter="AR"
dt_created = datetime.strptime(
in_page.meta.get(source_date_creation), meta_datetime_format
).timestamp()
except ValueError as err:
logger.error(
"[rss-plugin] Incompatible date found in meta of page: {}. Trace: {}".format(
in_page.file.abs_src_path, err
)
)
dt_updated = self.repo.log(
path,
n=1,
date="short",
format="%at",
if source_date_update != "git" and in_page.meta.get(source_date_update):
try:
dt_updated = datetime.strptime(
in_page.meta.get(source_date_update), meta_datetime_format
).timestamp()
except ValueError as err:
logger.error(
"[rss-plugin] Incompatible date found in meta of page: {}. Trace: {}".format(
in_page.file.abs_src_path, err
)
)

# explore git log
if self.git_is_valid:
try:
# only if dates have not been retrieved from page meta
if not dt_created:
dt_created = self.repo.log(
in_page.file.abs_src_path,
n=1,
date="short",
format="%at",
diff_filter="AR",
)
if not dt_updated:
dt_updated = self.repo.log(
in_page.file.abs_src_path,
n=1,
date="short",
format="%at",
)
except GitCommandError as err:
logging.warning(
"[rss-plugin] Unable to read git logs of '%s'. Is git log readable?"
" Falling back to build date. "
" Trace: %s" % (path, err)
" Trace: %s" % (in_page.file.abs_src_path, err)
)
except GitCommandNotFound as err:
logging.error(
Expand All @@ -129,7 +183,10 @@ def get_file_dates(self, path: str) -> Tuple[int, int]:
int(dt_updated),
)
else:
logging.warning("Dates could not be retrieved for page: %s." % path)
logging.warning(
"[rss-plugin] Dates could not be retrieved for page: %s."
% in_page.file.abs_src_path
)
return (
get_build_timestamp(),
get_build_timestamp(),
Expand Down
Loading

0 comments on commit 18066e2

Please sign in to comment.