Browse Source

Initial commit

Michael Li 6 years ago
parent
commit
7bf4836a7f
5 changed files with 99 additions and 0 deletions
  1. 2 0
      Readme.rst
  2. 41 0
      readtime/README.md
  3. 1 0
      readtime/__init__.py
  4. BIN
      readtime/demo.png
  5. 55 0
      readtime/readtime.py

+ 2 - 0
Readme.rst

@@ -220,6 +220,8 @@ Random article            Generates a html file which redirect to a random artic
 
 Read More link            Inserts an inline "read more" or "continue" link into the last html element of the object summary
 
+Readtime                  Adds article estimated read time calculator to the site, in the form of '<n> minutes'. 
+
 Related posts             Adds the ``related_posts`` variable to the article's context
 
 Render Math               Render mathematics in content via the MathJax Javascript engine

+ 41 - 0
readtime/README.md

@@ -0,0 +1,41 @@
+# 'pelican-readtime' - A Read Time Plugin for Pelican Static Site Generator
+
+An article estimated read time plugin for Pelican static site generator. After Pelican generated the content of each page, the plugin read through the generated HTML content and strip all the tags, count all the word, then utilize average human read speed to calculate the read time of each article. The read time is passed over to the 'content' object of the article so Jinja template can use it to display the read time on wherever appropriate.
+
+
+Demo
+-----
+The plugin can be embedded into your site's template and look like this:<br>
+![Pelican Read Time Demo](./demo.png )<br>
+An example can be found in my own blog [here](https://wayofnumbers.github.io/).<br>
+
+Usage
+-----
+
+This plugin only uses standard modules(re, html, math, etc), so no extra module installation like BeautifuSoup. To use it, just add the plugin name to the **pelicanconf.py** file.
+```python
+    PLUGINS=[ ... , 'pelican-readtime']
+```
+Then you can put the following code in whichever template you what, like *article.html*. 
+```html
+    {% if article.readtime %}
+    <div><b>Read in {{article.readtime.minutes}} min.</b></div>
+    {% endif %}
+```
+
+You can also add some styling to it like so:
+```html
+    {% if article.readtime %}
+    <span><p style="text-align:right; color:#aaaaaa; ">&nbsp Estimated read time: {{article.readtime.minutes}} min.</p></span>
+    {% endif %}
+```
+
+Credits
+-----
+This is a revised version of [jmaister's readtime plugin](https://github.com/jmaister/readtime). I added some more comments and tweaked the code so it runs smoothly on Python 3.6
+
+
+Reference
+-----
+[1] Wikipedia - [Words per minute](https://en.wikipedia.org/wiki/Words_per_minute) <br>
+[2] Medium - [Read Time](https://help.medium.com/hc/en-us/articles/214991667-Read-time) <br>

+ 1 - 0
readtime/__init__.py

@@ -0,0 +1 @@
+from .readtime import *

BIN
readtime/demo.png


+ 55 - 0
readtime/readtime.py

@@ -0,0 +1,55 @@
+import re
+import math
+
+from pelican import signals
+from html.parser import HTMLParser  #use html.parser for Python 3.6
+
+
+# http://en.wikipedia.org/wiki/Words_per_minute
+WPM = 230.0
+
+
+class MLStripper(HTMLParser):
+    def __init__(self):
+        super().__init__()    	# subclassing HTMLParser, also need to calling
+				# super class's '__init__' method
+        self.reset()
+        self.fed = []
+
+    #this method is called whenever a 'data' is encountered.
+    def handle_data(self, d):
+        self.fed.append(d)
+
+    # join all content word into one long sentence for further processing
+    def get_data(self):
+        return ''.join(self.fed)
+
+
+def strip_tags(html):
+    s = MLStripper()
+    s.feed(html)   		# Feed the class with html content, get the fed list
+    return s.get_data()
+
+
+def calculate_readtime(content_object):
+    if content_object._content is not None:
+        content = content_object._content	# get the content html from Pelican
+
+        text = strip_tags(content)		#strip tags and get long sentence
+        words = re.split(r'[^0-9A-Za-z]+', text) # split the long sentence into list of words
+
+        num_words = len(words)  	# count the words
+        minutes = int(math.ceil(num_words / WPM))  #calculate the minutes
+
+	    #set minimum read time to 1 minutes.
+        if minutes == 0:
+            minutes = 1
+
+        content_object.readtime = {
+            "minutes": minutes,
+        }
+
+
+def register():
+    signals.content_object_init.connect(calculate_readtime)   # connect with 'content_object_init' signal.
+