1
# Copyright (c) 2009 Entertainer Developers - See COPYING - GPLv2
2
'''Utilities for fetching feeds'''
6
from xml.dom import minidom
10
from entertainerlib.configuration import Configuration
13
class FeedEntryParser:
14
"""Will handle encoding and html for displaying feed entries"""
16
def strip_tags(self, text, valid_tags=None):
18
Strips a text string of all markup tags except the tags specified
19
@param text the text to be stripped
20
@param valid_tags a list of the allowed tags
31
if valid_tags is None:
34
#append closing tags to tag list
35
for next_tag in valid_tags:
36
valid_tag_list.append(next_tag)
37
valid_tag_list.append("/"+next_tag)
39
#setup a list to parse from input
40
parse_list = list(text)
43
while i < len(parse_list):
46
#we are into the tag and the tag name
52
if c == " " and in_tag_name:
53
#tag name has ended we are now into tag_attributes
55
tag_attributes += parse_list.pop(i)
57
#tag has finished let's clean up
61
if tag in valid_tag_list:
62
output += ("<" + tag + tag_attributes + ">")
66
#we are in a tag name lets append current char to tag
67
tag += parse_list.pop(i)
69
#we are in tag attributes lets append current char to
71
tag_attributes += parse_list.pop(i)
73
#not in a tag so append current char to output
74
output += parse_list.pop(i)
78
def strip_non_pango_tags(self, text):
80
Strips a text string of all non-pango tags
81
@param text the text to be stripped
83
return self.strip_tags(text,
84
["span", "b", "big", "i", "s", "sub", "sup", "small", "tt", "u"])
86
def convert(self, text):
88
This converts a text string into a format acceptable by a clutter
91
@param text the text to be converted
94
return self.strip_non_pango_tags(text).replace(' ', ' ')
98
"""Enables handling and parsing of opml files"""
100
def get_rss_feeds(self, filename):
102
returns list of rss feeds in the opml file
103
@param filename The OPML file
104
@return list(String) List of RSS feed urls
107
if os.path.isfile(filename):
108
#this loads the xml from the opml file into xmldoc
109
xmldoc = minidom.parse(filename)
111
xmldoc = minidom.parse(urllib.urlopen(filename))
112
#the rss feeds are in the xmlUrl attributes of the outline tags
113
#we loop through all the outline nodes in the opml file and add
114
#the contents of any xmlUrl attributes to the feeds variable
115
for node in xmldoc.getElementsByTagName('outline'):
116
url = node.getAttribute('xmlUrl')
117
#drop any items which are .opml files or empty string
118
#We do not recursively parse opml links as we could end up with an
120
if (url.strip() != "") and ((url.strip() [-5:]) != ".opml"):
122
#returns the list of rss feeds from the opml file
125
def get_liferea_opml(self, home_dir=os.path.expanduser("~")):
127
this returns either a empty string or the path to the current liferea
130
@param home_dir String defaults to ~
131
@return String Path to opml file
133
#we'll be storing the latest liferea config folder in path and the
134
#version number, if any, in curVersion
136
curVersion = float(0.0)
138
#loop through home and pick out any config folders matching .liferea*
139
filenames = [filename for filename in os.listdir(home_dir)
140
if filename.startswith(".liferea")]
142
if (len(filenames) <= 0):
143
#if there aren't any folders return an empty string
145
elif (len(filenames) == 1):
146
#if there's only 1 path found set it as the path
149
#in this case we have multiple posibilities
150
#liferea will store the config folder as .liferea or .liferea_9.9
151
#with 9.9 being the version number
152
#all we have todo is pick the largest version number or just the
153
#.liferea folder in that older
154
for fname in filenames:
155
if (fname [-3:] == "rea"):
156
if (curVersion == 0.0):
158
elif (float(fname [-3:])> curVersion):
159
curVersion = float(fname [-3:])
162
#check if the path variable gives us a valid path and return it if it
163
#does or an empty string if it doesn't
164
if os.path.isfile(home_dir + "/" + path + "/feedlist.opml"):
165
return home_dir + "/" + path + "/feedlist.opml"
169
class FeedConfigTools:
170
"""Enables Handling of Feed Config Widgets"""
173
"""Initialize to get access to the Configuration object"""
174
self.config = Configuration()
176
def add_file_feeds_to_widget(self, files, model, feeds, check=True):
178
This changes the input values so that the feeds in the files update
181
@param files list(String)
182
@param model GTKModel?
183
@param feeds list(String)
186
for opml_file in files:
187
#get the list of feeds from each file
188
opml_feeds = OPMLParser().get_rss_feeds(opml_file)
189
#add the feeds to the rss_list
190
for feed in opml_feeds:
191
feed_list.append(feed)
192
#only check if check is set to True
194
#check if the user really wants to add
195
dialog = gtk.MessageDialog(None, gtk.DIALOG_MODAL,
196
gtk.MESSAGE_WARNING, gtk.BUTTONS_OK_CANCEL,
197
"This will add " + str(len(feed_list)) +
198
" feeds to your feed list. Continue?")
200
status = dialog.run()
201
#If user has ok'd the request we can now add the feeds properly,
203
if(status == gtk.RESPONSE_OK):
204
#now we need append the feeds to self.feeds and content manager
205
self.add_feeds_to_widget(feed_list, model, feeds)
208
#now we need append the feeds to self.feeds and content manager
209
self.add_feeds_to_widget(feed_list, model, feeds)
211
def add_feeds_to_widget(self, feed_list, model, feeds):
213
This changes the input values so that the feeds in feed_list update
216
@param feed_list list(String)
217
@param model GTKModel?
218
@param feeds list(String)
221
for feed in feed_list:
222
#drop any items which are .opml files
223
#We do not recursively parse opml links as we could end up
224
#with an infinite loop
225
if (feed [-5:]) != ".opml":
226
#this is adding the feed to the content manager widget
229
#now we can parse the new feeds and add them
230
str_folders = ";".join(feeds)
231
self.config.write_content_value("RSS", "feeds", str_folders)
234
error = gtk.MessageDialog(None, gtk.DIALOG_MODAL,
235
gtk.MESSAGE_ERROR, gtk.BUTTONS_OK,
236
"IOError: There seems to be a problem with your selection.")