Added feed summary plugin.
This plugin allows to use the `Summary:` metadata as feed contents.
This commit is contained in:
33
feed_summary/Readme.md
Normal file
33
feed_summary/Readme.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Feed Summary #
|
||||
This plugin allows article summaries to be used in ATOM and RSS feeds instead of the entire article. It uses the
|
||||
built-in pelican `Summary:` metadata.
|
||||
|
||||
The summary of an article can either be set explicitly with the `Summary:` metadata attribute as described in the
|
||||
[pelican getting started docs](http://docs.getpelican.com/en/latest/getting_started.html#file-metadata),
|
||||
or automatically generated using the number of words specified in the
|
||||
[SUMMARY_MAX_LENGTH](http://docs.getpelican.com/en/latest/settings.html) setting.
|
||||
|
||||
## Usage ##
|
||||
To use this plugin, ensure the following are set in your `pelicanconf.py` file:
|
||||
|
||||
PLUGIN_PATH = '/path/to/pelican-plugins'
|
||||
PLUGINS = [
|
||||
'feed_summary',
|
||||
]
|
||||
'FEED_USE_SUMMARY' = True
|
||||
|
||||
The default value of `'FEED_USE_SUMMARY'` is `False`, so it must be set to `True` to enable the plugin, even if it is loaded.
|
||||
|
||||
This plugin is written for pelican 3.3 and later.
|
||||
|
||||
|
||||
## Implementation Notes ##
|
||||
|
||||
This plugin derives `FeedSummaryWriter` from the `Writer` class, duplicating code of the `Writer._add_item_to_the_feed` method.
|
||||
|
||||
When the `initialized` signal is sent, it alternates the `get_writer` method of the `Pelican` object to use `FeedSummaryWriter` instead of `Writer`.
|
||||
|
||||
A little hackish, but currently this can't be done otherwise via the regular plugin methods.
|
||||
|
||||
* *Initial Code (PR #36): Michelle L. Gill <michelle.lynn.gill@gmail.com>*
|
||||
* *Resumption of PR and Maintainer: Florian Jacob ( projects[PLUS]pelican[ÄT]florianjacob.de )*
|
||||
1
feed_summary/__init__.py
Normal file
1
feed_summary/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .feed_summary import *
|
||||
57
feed_summary/feed_summary.py
Normal file
57
feed_summary/feed_summary.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Feed Summary
|
||||
============
|
||||
|
||||
This plugin allows summaries to be used in feeds instead of the full length article.
|
||||
"""
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from jinja2 import Markup
|
||||
|
||||
import six
|
||||
if not six.PY3:
|
||||
from urlparse import urlparse
|
||||
else:
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from pelican import signals
|
||||
from pelican.writers import Writer
|
||||
from pelican.utils import set_date_tzinfo
|
||||
|
||||
from .magic_set import magic_set
|
||||
|
||||
class FeedSummaryWriter(Writer):
|
||||
def _add_item_to_the_feed(self, feed, item):
|
||||
if self.settings['FEED_USE_SUMMARY']:
|
||||
title = Markup(item.title).striptags()
|
||||
link = '%s/%s' % (self.site_url, item.url)
|
||||
feed.add_item(
|
||||
title=title,
|
||||
link=link,
|
||||
unique_id='tag:%s,%s:%s' % (urlparse(link).netloc,
|
||||
item.date.date(),
|
||||
urlparse(link).path.lstrip('/')),
|
||||
description=item.summary if hasattr(item, 'summary') else item.get_content(self.site_url),
|
||||
categories=item.tags if hasattr(item, 'tags') else None,
|
||||
author_name=getattr(item, 'author', ''),
|
||||
pubdate=set_date_tzinfo(item.modified if hasattr(item, 'modified') else item.date,
|
||||
self.settings.get('TIMEZONE', None)))
|
||||
else:
|
||||
super(FeedSummaryWriter, self)._add_item_to_the_feed(feed, item)
|
||||
|
||||
def set_feed_use_summary_default(pelican_object):
|
||||
# modifying DEFAULT_CONFIG doesn't have any effect at this point in pelican setup
|
||||
# everybody who uses DEFAULT_CONFIG is already used/copied it or uses the pelican_object.settings copy.
|
||||
|
||||
pelican_object.settings.setdefault('FEED_USE_SUMMARY', False)
|
||||
|
||||
def patch_pelican_writer(pelican_object):
|
||||
@magic_set(pelican_object)
|
||||
def get_writer(self):
|
||||
return FeedSummaryWriter(self.output_path,settings=self.settings)
|
||||
|
||||
def register():
|
||||
signals.initialized.connect(set_feed_use_summary_default)
|
||||
signals.initialized.connect(patch_pelican_writer)
|
||||
92
feed_summary/magic_set.py
Normal file
92
feed_summary/magic_set.py
Normal file
@@ -0,0 +1,92 @@
|
||||
import types
|
||||
import inspect
|
||||
|
||||
# Modifies class methods (or instances of them) on the fly
|
||||
# http://blog.ianbicking.org/2007/08/08/opening-python-classes/
|
||||
# http://svn.colorstudy.com/home/ianb/recipes/magicset.py
|
||||
|
||||
def magic_set(obj):
|
||||
"""
|
||||
Adds a function/method to an object. Uses the name of the first
|
||||
argument as a hint about whether it is a method (``self``), class
|
||||
method (``cls`` or ``klass``), or static method (anything else).
|
||||
Works on both instances and classes.
|
||||
|
||||
>>> class color:
|
||||
... def __init__(self, r, g, b):
|
||||
... self.r, self.g, self.b = r, g, b
|
||||
>>> c = color(0, 1, 0)
|
||||
>>> c # doctest: +ELLIPSIS
|
||||
<__main__.color instance at ...>
|
||||
>>> @magic_set(color)
|
||||
... def __repr__(self):
|
||||
... return '<color %s %s %s>' % (self.r, self.g, self.b)
|
||||
>>> c
|
||||
<color 0 1 0>
|
||||
>>> @magic_set(color)
|
||||
... def red(cls):
|
||||
... return cls(1, 0, 0)
|
||||
>>> color.red()
|
||||
<color 1 0 0>
|
||||
>>> c.red()
|
||||
<color 1 0 0>
|
||||
>>> @magic_set(color)
|
||||
... def name():
|
||||
... return 'color'
|
||||
>>> color.name()
|
||||
'color'
|
||||
>>> @magic_set(c)
|
||||
... def name(self):
|
||||
... return 'red'
|
||||
>>> c.name()
|
||||
'red'
|
||||
>>> @magic_set(c)
|
||||
... def name(cls):
|
||||
... return cls.__name__
|
||||
>>> c.name()
|
||||
'color'
|
||||
>>> @magic_set(c)
|
||||
... def pr(obj):
|
||||
... print obj
|
||||
>>> c.pr(1)
|
||||
1
|
||||
"""
|
||||
def decorator(func):
|
||||
is_class = (isinstance(obj, type)
|
||||
or isinstance(obj, types.ClassType))
|
||||
args, varargs, varkw, defaults = inspect.getargspec(func)
|
||||
if not args or args[0] not in ('self', 'cls', 'klass'):
|
||||
# Static function/method
|
||||
if is_class:
|
||||
replacement = staticmethod(func)
|
||||
else:
|
||||
replacement = func
|
||||
elif args[0] == 'self':
|
||||
if is_class:
|
||||
replacement = func
|
||||
else:
|
||||
def replacement(*args, **kw):
|
||||
return func(obj, *args, **kw)
|
||||
try:
|
||||
replacement.func_name = func.func_name
|
||||
except:
|
||||
pass
|
||||
else:
|
||||
if is_class:
|
||||
replacement = classmethod(func)
|
||||
else:
|
||||
def replacement(*args, **kw):
|
||||
return func(obj.__class__, *args, **kw)
|
||||
try:
|
||||
replacement.func_name = func.func_name
|
||||
except:
|
||||
pass
|
||||
setattr(obj, func.func_name, replacement)
|
||||
return replacement
|
||||
return decorator
|
||||
|
||||
if __name__ == '__main__':
|
||||
import doctest
|
||||
doctest.testmod()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user