Przeglądaj źródła

Added feed summary plugin.
This plugin allows to use the `Summary:` metadata as feed contents.

Florian Jacob 10 lat temu
rodzic
commit
2a564dce1a

+ 33 - 0
feed_summary/Readme.md

@@ -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 - 0
feed_summary/__init__.py

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

+ 57 - 0
feed_summary/feed_summary.py

@@ -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 - 0
feed_summary/magic_set.py

@@ -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()
+    
+