Added feed summary plugin.

This plugin allows to use the `Summary:` metadata as feed contents.
This commit is contained in:
Florian Jacob
2013-11-27 23:00:02 +01:00
parent bd12282f92
commit 2a564dce1a
4 changed files with 183 additions and 0 deletions

33
feed_summary/Readme.md Normal file
View 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
View File

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

View 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
View 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()