1 #!/usr/bin/env python2.5
4 # Copyright (c) 2007-2008 INdT.
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 # ============================================================================
21 # Author : Yves Marcoz
23 # Description : Simple RSS Reader
24 # ============================================================================
26 from os.path import isfile
27 from os.path import isdir
35 #CONFIGDIR="/home/user/.feedingit/"
38 return md5.new(string).hexdigest()
41 # Contains all the info about a single feed (articles, ...), and expose the data
42 def __init__(self, name, url):
48 self.updateTime = "Never"
50 def editFeed(self, url):
53 def saveFeed(self, configdir):
54 file = open(configdir+getId(self.name), "w")
55 pickle.dump(self, file )
58 def updateFeed(self, configdir, expiryTime=24):
59 # Expiry time is in hours
60 tmp=feedparser.parse(self.url)
61 # Check if the parse was succesful (number of entries > 0, else do nothing)
62 if len(tmp["entries"])>0:
63 #reversedEntries = self.getEntries()
64 #reversedEntries.reverse()
66 for entry in tmp["entries"]:
67 tmpIds.append(self.getUniqueId(-1, entry))
68 for entry in self.getEntries():
69 currentTime = time.time()
70 expiry = float(expiryTime) * 3600.
71 if entry.has_key("updated_parsed"):
72 articleTime = time.mktime(entry["updated_parsed"])
73 if currentTime - articleTime < expiry:
74 id = self.getUniqueId(-1, entry)
76 tmp["entries"].append(entry)
78 self.entries = tmp["entries"]
80 # Initialize the new articles to unread
81 tmpReadItems = self.readItems
83 for index in range(self.getNumberOfEntries()):
84 if not tmpReadItems.has_key(self.getUniqueId(index)):
85 self.readItems[self.getUniqueId(index)] = False
87 self.readItems[self.getUniqueId(index)] = tmpReadItems[self.getUniqueId(index)]
88 if self.readItems[self.getUniqueId(index)]==False:
89 self.countUnread = self.countUnread + 1
91 self.updateTime = time.asctime()
92 self.saveFeed(configdir)
94 def setEntryRead(self, index):
95 if self.readItems[self.getUniqueId(index)]==False:
96 self.countUnread = self.countUnread - 1
97 self.readItems[self.getUniqueId(index)] = True
99 def setEntryUnread(self, index):
100 if self.readItems[self.getUniqueId(index)]==True:
101 self.countUnread = self.countUnread + 1
102 self.readItems[self.getUniqueId(index)] = False
104 def isEntryRead(self, index):
105 return self.readItems[self.getUniqueId(index)]
107 def getTitle(self, index):
108 return self.entries[index]["title"]
110 def getLink(self, index):
111 return self.entries[index]["link"]
113 def getDate(self, index):
115 return self.entries[index]["updated_parsed"]
117 return time.localtime()
119 def getUniqueId(self, index, entry=None):
121 entry = self.entries[index]
122 if entry.has_key("updated_parsed"):
123 return getId(time.strftime("%a, %d %b %Y %H:%M:%S",entry["updated_parsed"]) + entry["title"])
124 elif entry.has_key("link"):
125 return getId(entry["link"] + entry["title"])
127 return getId(entry["title"])
129 def getUpdateTime(self):
130 return self.updateTime
132 def getEntries(self):
138 def getNumberOfUnreadItems(self):
139 return self.countUnread
141 def getNumberOfEntries(self):
142 return len(self.entries)
144 def getItem(self, index):
146 return self.entries[index]
150 def getContent(self, index):
152 entry = self.entries[index]
153 if entry.has_key('summary'):
154 content = entry.get('summary', '')
155 if entry.has_key('content'):
156 if len(entry.content[0].value) > len(content):
157 content = entry.content[0].value
159 content = entry.get('description', '')
162 def getArticle(self, index):
163 self.setEntryRead(index)
164 entry = self.entries[index]
165 title = entry.get('title', 'No title')
166 #content = entry.get('content', entry.get('summary_detail', {}))
167 content = self.getContent(index)
169 link = entry.get('link', 'NoLink')
170 if entry.has_key("updated_parsed"):
171 date = time.strftime("%a, %d %b %Y %H:%M:%S",entry["updated_parsed"])
172 elif entry.has_key("published_parsed"):
173 date = time.strftime("%a, %d %b %Y %H:%M:%S", entry["published_parsed"])
176 #text = '''<div style="color: black; background-color: white;">'''
177 text = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>'
178 text += '<head><style> body {-webkit-user-select: none;} </style></head>'
179 text += '<body><div><a href=\"' + link + '\">' + title + "</a>"
180 text += "<BR /><small><i>Date: " + date + "</i></small></div>"
181 text += "<BR /><BR />"
186 class ArchivedArticles(Feed):
187 def addArchivedArticle(self, title, link, updated_parsed, configdir):
189 entry["title"] = title
191 entry["downloaded"] = False
192 entry["summary"] = '<a href=\"' + link + '\">' + title + "</a>"
193 entry["updated_parsed"] = updated_parsed
194 entry["time"] = time.time()
195 self.entries.append(entry)
196 self.readItems[self.getUniqueId(len(self.entries)-1)] = False
197 self.countUnread = self.countUnread + 1
198 self.saveFeed(configdir)
201 def updateFeed(self, configdir, expiryTime=24):
203 for entry in self.getEntries():
204 if not entry["downloaded"]:
206 f = urllib2.urlopen(entry["link"])
207 entry["summary"] = f.read()
209 if len(entry["summary"]) > 0:
210 entry["downloaded"] = True
211 entry["time"] = time.time()
212 self.setEntryUnread(index)
215 currentTime = time.time()
216 expiry = float(expiryTime) * 3600
217 if currentTime - entry["time"] > expiry:
218 self.entries.remove(entry)
220 self.updateTime = time.asctime()
221 self.saveFeed(configdir)
223 def getArticle(self, index):
224 self.setEntryRead(index)
225 content = self.getContent(index)
230 # Lists all the feeds in a dictionary, and expose the data
231 def __init__(self, configdir):
232 self.configdir = configdir
234 if isfile(self.configdir+"feeds.pickle"):
235 file = open(self.configdir+"feeds.pickle")
236 self.listOfFeeds = pickle.load(file)
239 self.listOfFeeds = {getId("Slashdot"):{"title":"Slashdot", "url":"http://rss.slashdot.org/Slashdot/slashdot"}, }
240 if self.listOfFeeds.has_key("font"):
241 del self.listOfFeeds["font"]
242 if self.listOfFeeds.has_key("feedingit-order"):
243 self.sortedKeys = self.listOfFeeds["feedingit-order"]
245 self.sortedKeys = self.listOfFeeds.keys()
246 if "font" in self.sortedKeys:
247 self.sortedKeys.remove("font")
248 self.sortedKeys.sort(key=lambda obj: self.getFeedTitle(obj))
249 list = self.sortedKeys[:]
255 #if key.startswith('d8'):
256 #traceback.print_exc()
257 self.sortedKeys.remove(key)
259 #print key in self.sortedKeys
260 #print "d8eb3f07572892a7b5ed9c81c5bb21a2" in self.sortedKeys
261 #print self.listOfFeeds["d8eb3f07572892a7b5ed9c81c5bb21a2"]
262 self.closeCurrentlyDisplayedFeed()
265 def addArchivedArticle(self, key, index):
266 title = self.getFeed(key).getTitle(index)
267 link = self.getFeed(key).getLink(index)
268 date = self.getFeed(key).getDate(index)
269 if not self.listOfFeeds.has_key(getId("Archived Articles")):
270 self.listOfFeeds[getId("Archived Articles")] = {"title":"Archived Articles", "url":""}
271 self.sortedKeys.append(getId("Archived Articles"))
272 self.feeds[getId("Archived Articles")] = ArchivedArticles("Archived Articles", "")
275 self.getFeed(getId("Archived Articles")).addArchivedArticle(title, link, date, self.configdir)
277 def loadFeed(self, key):
278 if isfile(self.configdir+key):
279 file = open(self.configdir+key)
280 self.feeds[key] = pickle.load(file)
284 title = self.listOfFeeds[key]["title"]
285 url = self.listOfFeeds[key]["url"]
286 self.feeds[key] = Feed(title, url)
288 def updateFeeds(self, expiryTime=24):
289 for key in self.getListOfFeeds():
290 self.feeds[key].updateFeed(self.configdir, expiryTime)
292 def updateFeed(self, key, expiryTime=24):
293 self.feeds[key].updateFeed(self.configdir, expiryTime)
295 def editFeed(self, key, title, url):
296 self.listOfFeeds[key]["title"] = title
297 self.listOfFeeds[key]["url"] = url
298 self.feeds[key].editFeed(url)
300 def getFeed(self, key):
301 return self.feeds[key]
303 def getFeedUpdateTime(self, key):
304 #print self.listOfFeeds.has_key(key)
305 return self.feeds[key].getUpdateTime()
307 def getFeedNumberOfUnreadItems(self, key):
308 return self.feeds[key].getNumberOfUnreadItems()
310 def getFeedTitle(self, key):
311 return self.listOfFeeds[key]["title"]
313 def getFeedUrl(self, key):
314 return self.listOfFeeds[key]["url"]
316 def getListOfFeeds(self):
317 return self.sortedKeys
319 def addFeed(self, title, url):
320 if not self.listOfFeeds.has_key(getId(title)):
321 self.listOfFeeds[getId(title)] = {"title":title, "url":url}
322 self.sortedKeys.append(getId(title))
324 self.feeds[getId(title)] = Feed(title, url)
329 def removeFeed(self, key):
330 del self.listOfFeeds[key]
331 self.sortedKeys.remove(key)
333 if isfile(self.configdir+key):
334 remove(self.configdir+key)
337 def saveConfig(self):
338 self.listOfFeeds["feedingit-order"] = self.sortedKeys
339 file = open(self.configdir+"feeds.pickle", "w")
340 pickle.dump(self.listOfFeeds, file)
343 def moveUp(self, key):
344 index = self.sortedKeys.index(key)
345 self.sortedKeys[index] = self.sortedKeys[index-1]
346 self.sortedKeys[index-1] = key
348 def moveDown(self, key):
349 index = self.sortedKeys.index(key)
350 index2 = (index+1)%len(self.sortedKeys)
351 self.sortedKeys[index] = self.sortedKeys[index2]
352 self.sortedKeys[index2] = key
354 def setCurrentlyDisplayedFeed(self, key):
355 self.currentlyDisplayedFeed = key
356 def closeCurrentlyDisplayedFeed(self):
357 self.currentlyDisplayedFeed = False
358 def getCurrentlyDisplayedFeed(self):
359 return self.currentlyDisplayedFeed
361 if __name__ == "__main__":
362 listing = Listing('/home/user/.feedingit/')
363 list = listing.getListOfFeeds()[:]
366 if key.startswith('d8'):
367 print listing.getFeedUpdateTime(key)