My favorites | Sign in
Project Logo
                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
from django import template
from django.conf import settings
from django.core.cache import cache
from cPickle import loads, dumps, HIGHEST_PROTOCOL
import datetime
import feedparser
import re
import time

def _getdefault(name, default=None):
try:
default = getattr(settings, name)
except: pass
return default

FEEDUTIL_NUM_POSTS = _getdefault('FEEDUTIL_NUM_POSTS', -1)
FEEDUTIL_CACHE_MIN = _getdefault('FEEDUTIL_CACHE_MIN', 30)
FEEDUTIL_SUMMARY_LEN = _getdefault('FEEDUTIL_SUMMARY_LEN', 150)
FEEDUTIL_SUMMARY_HTML_WORDS = _getdefault('FEEDUTIL_SUMMARY_HTML_WORDS', 25)

register = template.Library()

def summarize(text):
cleaned = template.defaultfilters.striptags(text)
l = len(cleaned)
if len(cleaned) > FEEDUTIL_SUMMARY_LEN:
cleaned = cleaned[:FEEDUTIL_SUMMARY_LEN] + '...'
return cleaned

def summarize_html(text):
return template.defaultfilters.truncatewords_html(text,
FEEDUTIL_SUMMARY_HTML_WORDS) + ' ...'

def pull_feed(feed_url, posts_to_show=None, cache_expires=None):
if posts_to_show is None: posts_to_show = FEEDUTIL_NUM_POSTS
if cache_expires is None: cache_expires = FEEDUTIL_CACHE_MIN
cachename = 'feed_cache_' + template.defaultfilters.slugify(feed_url)
posts = []
data = None
if cache_expires > 0:
data = cache.get(cachename)
if data is None:
# load feed
try:
feed = feedparser.parse(feed_url)
entries = feed['entries']
#if posts_to_show > 0 and len(entries) > posts_to_show:
# entries = entries[:posts_to_show]
posts = [ {
'title': entry.title,
'author': entry.author if entry.has_key('author') else '',
'summary': summarize(entry.summary if entry.has_key('summary') else entry.content[0]['value']),
'summary_html': summarize_html(entry.description if entry.has_key('description') else entry.content[0]['value']),
'content': entry.description if entry.has_key('description') else entry.content[0]['value'],
'url': entry.link,
'comments': entry.comments if entry.has_key('comments') else '',
'published': datetime.datetime.fromtimestamp(time.mktime(entry.updated_parsed)) if entry.has_key('updated_parsed') else '', }
for entry in entries ]
except:
if settings.DEBUG:
raise
return []
if cache_expires > 0:
cache.set(cachename, posts, cache_expires*60)
else:
#load feed from cache
posts = data

if posts_to_show > 0 and len(posts) > posts_to_show:
posts = posts[:posts_to_show]

return posts

@register.inclusion_tag('feedutil/feed.html')
def feed(feed_url, posts_to_show=None, cache_expires=None):
"""
Render an RSS/Atom feed using the 'feedutil/feed.html' template.

::
{% feed feed_url [posts_to_show] [cache_expires] %}
{% feed "https://foo.net/timeline?max=5&format=rss" 5 60 %}


feed_url: full url to the feed (required)
posts_to_show: Number of posts to pull. <=0 for all
(default: settings.FEEDUTIL_NUM_POSTS or -1)
cache_expired: Number of minuites for the cache. <=0 for no cache.
(default: settings.FEEDUTIL_CACHE_MIN or 30)

"""
return { 'posts': pull_feed(feed_url, posts_to_show, cache_expires) }

class GetFeedNode(template.Node):
def __init__(self, var_name, feed_url, posts_to_show=None,
cache_expires=None):
self.var_name = var_name
self.feed_url = feed_url
self.posts_to_show = posts_to_show
self.cache_expires = cache_expires
def render(self, context):
posts_to_show = cache_expires = None
try:
feed_url = template.resolve_variable(self.feed_url, context)
except:
if settings.DEBUG:
raise
context[self.var_name] = []
return ''
if self.posts_to_show is not None:
try:
posts_to_show = template.resolve_variable(self.posts_to_show,
context)
except template.VariableDoesNotExist:
if settings.DEBUG:
raise
if self.cache_expires is not None:
try:
cache_expires = template.resolve_variable(self.cache_expires,
context)
except template.VariableDoesNotExist:
if settings.DEBUG:
raise
context[self.var_name] = pull_feed(feed_url,
posts_to_show,
cache_expires)
return ''

@register.tag
def get_feed(parser, token):
"""
Pull a RSS or Atom feed into the context as the supplied variable.

::
{% get_feed feed_url [posts_to_show] [cache_expires] as var %}
{% get_feed "https://foo.net/timeline?max=5&format=rss" 5 60 as myfeed %}

feed_url: full url to the feed (required)
posts_to_show: Number of posts to pull. <=0 for all
(default: settings.FEEDUTIL_NUM_POSTS or -1)
cache_expired: Number of minuites for the cache. <=0 for no cache.
(default: settings.FEEDUTIL_CACHE_MIN or 30)
var: Name of variable to set the feed to in the current context


Format of var:

::

[ { 'title': "A title" , 'summary': "The summary",
'url': "http://foo.net/a-title",
'published': datetime(10, 20, 2007) },
... ]


"""
args = token.split_contents()
args.pop(0)
if len(args) < 3 or len(args) > 5 or args[-2] != 'as':
raise template.TemplateSyntaxError("Malformed arguments to get_feed tag.")
nargs = [args[-1]] + args[:-2]
return GetFeedNode(*nargs)
return { 'posts': pull_feed(feed_url, posts_to_show, cache_expires) }
Show details Hide details

Change log

r4 by doug.napoleone on Jun 01, 2008   Diff
fixed summary bug when feed had a
'summary' field.

Go to: 
Project members, sign in to write a code review

Older revisions

r3 by doug.napoleone on May 31, 2008   Diff
made to work when there is no cache
set but requires the
FEEDUTIL_CACHE_MIN to be set to 0

r2 by doug.napoleone on Mar 17, 2008   Diff
Initial import from PyCon-Tech

All revisions of this file

File info

Size: 6081 bytes, 162 lines

File properties

svn:eol-style
native
svn:keywords
Id HeadURL LastChangedRevision
Hosted by Google Code