diff options
Diffstat (limited to 'extra_plugins')
| -rw-r--r-- | extra_plugins/README.txt | 62 | ||||
| -rw-r--r-- | extra_plugins/command_planetoid.plugin | 9 | ||||
| -rw-r--r-- | extra_plugins/command_planetoid/__init__.py | 248 | ||||
| -rw-r--r-- | extra_plugins/command_planetoid/index.tmpl | 26 | ||||
| -rw-r--r-- | extra_plugins/command_planetoid/post.tmpl | 10 | ||||
| -rw-r--r-- | extra_plugins/task_localsearch/README.txt | 12 | ||||
| -rw-r--r-- | extra_plugins/task_mustache/__init__.py | 3 |
7 files changed, 356 insertions, 14 deletions
diff --git a/extra_plugins/README.txt b/extra_plugins/README.txt new file mode 100644 index 0000000..2a04614 --- /dev/null +++ b/extra_plugins/README.txt @@ -0,0 +1,62 @@ +Extra Plugins +============= + +These are plugins that may not be widely used or that are a bit too radical or +experimental for the general public. + +To enable them for you, create a ``plugins/`` folder in your site, and copy +both the ``.plugin`` file and the matching ``.py`` file or folder. + +Planetoid +--------- + +This plugin converts Nikola into the equivalent of `Planet <http://www.planetplanet.org/>`_ +a feed aggregator. It requires `PeeWee <https://github.com/coleifer/peewee>`_ and +`Feedparser <http://code.google.com/p/feedparser/>`_ to work. + +It has a configuration option: PLANETOID_REFRESH which is the number of minutes +before retrying a feed (defaults to 60). + +You need to create a ``feeds`` file containing the data of which feeds you want to +aggregate. The format is very simple:: + + # Roberto Alsina + http://feeds2.feedburner.com/PostsInLateralOpinionAboutPython + Roberto Alsina + +#. Lines that start with ``#`` are comments and ignored. +#. Lines that start with http are feed URLs. +#. URL lines have to be followed by the "real name" of the feed. + +FIXME: explain the planetoid theme stuff + +After all that is in place, just run ``nikola build`` and you'll get +a planet. + +Local Search +------------ + +If you don't want to depend on google or duckduckgo to implement search for you, +or just want it to wok even if you are offline, enable this plugin and the +search will be performed client side. + +This plugin implements a Tipue-based local search for your site. + +To use it, copy task_localsearch.plugin and task_localsearch +into a plugins/ folder in your nikola site. + +After you build your site, you will have several new files in assets/css and assets/js +and a search.html that you can use as a basis for using this in your site. + +For more information about how to customize it and use it, please refer to the tipue +docs at http://www.tipue.com/search/ + +Tipue is under an MIT license (see MIT-LICENSE.txt) + + +Mustache +-------- + +This task gives you a ``mustache.html`` file which lets you access your whole +blog without reloading the page, using client-side templates. Makes it much +faster and modern ;-) diff --git a/extra_plugins/command_planetoid.plugin b/extra_plugins/command_planetoid.plugin new file mode 100644 index 0000000..8636d49 --- /dev/null +++ b/extra_plugins/command_planetoid.plugin @@ -0,0 +1,9 @@ +[Core] +Name = planetoid +Module = command_planetoid + +[Documentation] +Author = Roberto Alsina +Version = 0.1 +Website = http://nikola.ralsina.com.ar +Description = Maintain a planet-like site diff --git a/extra_plugins/command_planetoid/__init__.py b/extra_plugins/command_planetoid/__init__.py new file mode 100644 index 0000000..7ccb19e --- /dev/null +++ b/extra_plugins/command_planetoid/__init__.py @@ -0,0 +1,248 @@ +# -*- coding: utf-8 -*- +# Copyright (c) 2012 Roberto Alsina y otros. + +# Permission is hereby granted, free of charge, to any +# person obtaining a copy of this software and associated +# documentation files (the "Software"), to deal in the +# Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the +# Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice +# shall be included in all copies or substantial portions of +# the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS +# OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import print_function +import codecs +import datetime +import hashlib +from optparse import OptionParser +import os + +from doit.tools import timeout +import feedparser +import peewee + +from nikola.plugin_categories import Command, Task +from nikola.utils import config_changed + + +class Feed(peewee.Model): + name = peewee.CharField() + url = peewee.CharField(max_length=200) + last_status = peewee.CharField(null=True) + etag = peewee.CharField(max_length=200) + last_modified = peewee.DateTimeField() + + +class Entry(peewee.Model): + date = peewee.DateTimeField() + feed = peewee.ForeignKeyField(Feed) + content = peewee.TextField(max_length=20000) + link = peewee.CharField(max_length=200) + title = peewee.CharField(max_length=200) + guid = peewee.CharField(max_length=200) + + +class Planetoid(Command, Task): + """Maintain a planet-like thing.""" + name = "planetoid" + + def init_db(self): + # setup database + Feed.create_table(fail_silently=True) + Entry.create_table(fail_silently=True) + + def gen_tasks(self): + self.init_db() + for task in self.task_load_feeds(): + yield task + for task in self.task_update_feeds(): + yield task + for task in self.task_generate_posts(): + yield task + + def run(self, *args): + self.init_db() + parser = OptionParser(usage="nikola %s [options]" % self.name) + (options, args) = parser.parse_args(list(args)) + + def task_load_feeds(self): + "Read the feeds file, add it to the database." + feeds = [] + feed = name = None + for line in codecs.open('feeds', 'r', 'utf-8'): + line = line.strip() + if line.startswith("#"): + continue + elif line.startswith(u'http'): + feed = line + elif line: + name = line + if feed and name: + feeds.append([feed, name]) + feed = name = None + + def add_feed(name, url): + f = Feed.create( + name=name, + url=url, + etag='foo', + last_modified=datetime.datetime(1970, 1, 1), + ) + f.save() + + def update_feed_url(feed, url): + feed.url = url + feed.save() + + for feed, name in feeds: + f = Feed.select().where(Feed.name == name) + if not list(f): + yield { + 'basename': self.name, + 'name': name.encode('utf8'), + 'actions': ((add_feed, (name, feed)), ), + 'file_dep': ['feeds'], + } + elif list(f)[0].url != feed: + yield { + 'basename': self.name, + 'name': (u'updating_' + name).encode('utf8'), + 'actions': ((update_feed_url, (list(f)[0], feed)), ), + } + + def task_update_feeds(self): + """Download feed contents, add entries to the database.""" + def update_feed(feed): + modified = feed.last_modified.timetuple() + etag = feed.etag + try: + parsed = feedparser.parse( + feed.url, + etag=etag, + modified=modified + ) + feed.last_status = str(parsed.status) + except: # Probably a timeout + # TODO: log failure + return + if parsed.feed.get('title'): + print(parsed.feed.title) + else: + print(feed.url) + feed.etag = parsed.get('etag', 'foo') + modified = tuple(parsed.get('date_parsed', (1970, 1, 1)))[:6] + print("==========>", modified) + modified = datetime.datetime(*modified) + feed.last_modified = modified + feed.save() + # No point in adding items from missinfg feeds + if parsed.status > 400: + # TODO log failure + return + for entry_data in parsed.entries: + print("=========================================") + date = entry_data.get('published_parsed', None) + if date is None: + date = entry_data.get('updated_parsed', None) + if date is None: + print("Can't parse date from:") + print(entry_data) + return False + print("DATE:===>", date) + date = datetime.datetime(*(date[:6])) + title = "%s: %s" % (feed.name, entry_data.get('title', 'Sin tÃtulo')) + content = entry_data.get('content', None) + if content: + content = content[0].value + if not content: + content = entry_data.get('description', None) + if not content: + content = entry_data.get('summary', 'Sin contenido') + guid = str(entry_data.get('guid', entry_data.link)) + link = entry_data.link + print(repr([date, title])) + e = list(Entry.select().where(Entry.guid == guid)) + print( + repr(dict( + date=date, + title=title, + content=content, + guid=guid, + feed=feed, + link=link, + )) + ) + if not e: + entry = Entry.create( + date=date, + title=title, + content=content, + guid=guid, + feed=feed, + link=link, + ) + else: + entry = e[0] + entry.date = date + entry.title = title + entry.content = content + entry.link = link + entry.save() + for feed in Feed.select(): + task = { + 'basename': self.name, + 'name': str(feed.url), + 'actions': [(update_feed, (feed, ))], + 'uptodate': [timeout(datetime.timedelta(minutes= + self.site.config.get('PLANETOID_REFRESH', 60)))], + } + yield task + + def task_generate_posts(self): + """Generate post files for the blog entries.""" + def gen_id(entry): + h = hashlib.md5() + h.update(entry.feed.name.encode('utf8')) + h.update(entry.guid) + return h.hexdigest() + + def generate_post(entry): + unique_id = gen_id(entry) + meta_path = os.path.join('posts', unique_id + '.meta') + post_path = os.path.join('posts', unique_id + '.txt') + with codecs.open(meta_path, 'wb+', 'utf8') as fd: + fd.write(u'%s\n' % entry.title.replace('\n', ' ')) + fd.write(u'%s\n' % unique_id) + fd.write(u'%s\n' % entry.date.strftime('%Y/%m/%d %H:%M')) + fd.write(u'\n') + fd.write(u'%s\n' % entry.link) + with codecs.open(post_path, 'wb+', 'utf8') as fd: + fd.write(u'.. raw:: html\n\n') + content = entry.content + if not content: + content = u'Sin contenido' + for line in content.splitlines(): + fd.write(u' %s\n' % line) + + for entry in Entry.select().order_by(Entry.date.desc()): + entry_id = gen_id(entry) + yield { + 'basename': self.name, + 'targets': [os.path.join('posts', entry_id + '.meta'), os.path.join('posts', entry_id + '.txt')], + 'name': entry_id, + 'actions': [(generate_post, (entry,))], + 'uptodate': [config_changed({1: entry})] + } diff --git a/extra_plugins/command_planetoid/index.tmpl b/extra_plugins/command_planetoid/index.tmpl new file mode 100644 index 0000000..da9ff5d --- /dev/null +++ b/extra_plugins/command_planetoid/index.tmpl @@ -0,0 +1,26 @@ +## -*- coding: utf-8 -*- +<%inherit file="base.tmpl"/> +<%block name="content"> + % for post in posts: + <div style="border: 2px solid darkgrey; margin-bottom: 12px; border-radius: 4px; padding:12px; overflow: auto;"> + <a href="${post.link}"><h1>${post.title(lang)}</a> + <small> + Publicado: ${post.date} + </small></h1> + ${post.text(lang)} + </div> + % endfor + <div> +<ul class="pager"> + %if prevlink: + <li class="previous"> + <a href="${prevlink}">← Posts posteriores</a> + </li> + %endif + %if nextlink: + <li class="next"> + <a href="${nextlink}">Posts anteriores →</a> + </li> + %endif +</ul> +</%block> diff --git a/extra_plugins/command_planetoid/post.tmpl b/extra_plugins/command_planetoid/post.tmpl new file mode 100644 index 0000000..2c4c220 --- /dev/null +++ b/extra_plugins/command_planetoid/post.tmpl @@ -0,0 +1,10 @@ +## -*- coding: utf-8 -*- +<html> +<body> +<script type="text/javascript"> +<!-- +window.location = "${post.link}" +//--> +</script> +Redirecting you to <a href="${post.link}">the original location.</a> +</body>
\ No newline at end of file diff --git a/extra_plugins/task_localsearch/README.txt b/extra_plugins/task_localsearch/README.txt deleted file mode 100644 index f6f2d64..0000000 --- a/extra_plugins/task_localsearch/README.txt +++ /dev/null @@ -1,12 +0,0 @@ -This plugin implements a Tipue-based local search for your site. - -To use it, copy task_localsearch.plugin and task_localsearch -into a plugins/ folder in your nikola site. - -After you build your site, you will have several new files in assets/css and assets/js -and a search.html that you can use as a basis for using this in your site. - -For more information about how to customize it and use it, please refer to the tipue -docs at http://www.tipue.com/search/ - -Tipue is under an MIT license (see MIT-LICENSE.txt) diff --git a/extra_plugins/task_mustache/__init__.py b/extra_plugins/task_mustache/__init__.py index 98e52d1..0d0e87d 100644 --- a/extra_plugins/task_mustache/__init__.py +++ b/extra_plugins/task_mustache/__init__.py @@ -126,8 +126,7 @@ class Mustache(Task): if langname == lang: continue translations.append({'name': - kw["messages"][langname]["Read in" - "English"], + kw["messages"][langname]["Read in English"], 'link': "javascript:load_data('%s');" % post.permalink(langname).replace( ".html", ".json")}) |
