0.2.1-2 - Threaded download of images
[feedingit] / src / rss.py
1 #!/usr/bin/env python2.5
2
3
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.
9 #
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.
14 #
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/>.
17 #
18
19 # ============================================================================
20 # Name        : FeedingIt.py
21 # Author      : Yves Marcoz
22 # Version     : 0.2.0
23 # Description : Simple RSS Reader
24 # ============================================================================
25
26 from os.path import isfile
27 from os.path import isdir
28 from os import remove
29 import pickle
30 import md5
31 import feedparser
32 import time
33
34 CONFIGDIR="/home/user/.feedingit/"
35
36 def getId(string):
37     return md5.new(string).hexdigest()
38
39 class Feed:
40     # Contains all the info about a single feed (articles, ...), and expose the data
41     def __init__(self, name, url):
42         self.entries = []
43         self.readItems = {}
44         self.countUnread = 0
45         self.name = name
46         self.url = url
47         self.updateTime = "Never"
48
49     def saveFeed(self):
50         file = open(CONFIGDIR+getId(self.name), "w")
51         pickle.dump(self, file )
52         file.close()
53
54     def updateFeed(self):
55         tmp=feedparser.parse(self.url)
56         # Check if the parse was succesful (number of entries > 0, else do nothing)
57         if len(tmp["entries"])>0:
58            self.tmpReadItems = self.readItems
59            self.readItems = {}
60            self.updateTime = time.asctime()
61            self.entries = tmp["entries"]
62            self.countUnread = 0
63            # Initialize the new articles to unread
64            for index in range(self.getNumberOfEntries()):
65                if not self.tmpReadItems.has_key(self.getUniqueId(index)):
66                    self.readItems[self.getUniqueId(index)] = False
67                else:
68                    self.readItems[self.getUniqueId(index)] = self.tmpReadItems[self.getUniqueId(index)]
69                if self.readItems[self.getUniqueId(index)]==False:
70                   self.countUnread = self.countUnread + 1
71            del tmp
72            self.saveFeed()
73     
74     def setEntryRead(self, index):
75         if self.readItems[self.getUniqueId(index)]==False:
76             self.countUnread = self.countUnread - 1
77             self.readItems[self.getUniqueId(index)] = True
78     
79     def isEntryRead(self, index):
80         return self.readItems[self.getUniqueId(index)]
81     
82     def getTitle(self, index):
83         return self.entries[index]["title"]
84     
85     def getUniqueId(self,index):
86         entry = self.entries[index]
87         if entry.has_key("updated_parsed"):
88             return getId(time.strftime("%a, %d %b %Y %H:%M:%S",entry["updated_parsed"]) + entry["title"])
89         elif entry.has_key("link"):
90             return getId(entry["link"] + entry["title"])
91         else:
92             return getId(entry["title"])
93     
94     def getUpdateTime(self):
95         return self.updateTime
96     
97     def getEntries(self):
98         try:
99             return self.entries
100         except:
101             return []
102     
103     def getNumberOfUnreadItems(self):
104         return self.countUnread
105     
106     def getNumberOfEntries(self):
107         return len(self.entries)
108     
109     def getItem(self, index):
110         try:
111             return self.entries[index]
112         except:
113             return []
114     
115     def getContent(self, index):
116         entry = self.entries[index]
117         if entry.has_key('content'):
118             content = entry.content[0].value
119         else:
120             content = entry.get('summary', '')
121         return content
122     
123     def getArticle(self, index):
124         self.setEntryRead(index)
125         entry = self.entries[index]
126         title = entry.get('title', 'No title')
127         #content = entry.get('content', entry.get('summary_detail', {}))
128         content = self.getContent(index)
129
130         link = entry.get('link', 'NoLink')
131         if entry.has_key("updated_parsed"):
132             date = time.strftime("%a, %d %b %Y %H:%M:%S",entry["updated_parsed"])
133         elif entry.has_key("published_parsed"):
134             date = time.strftime("%a, %d %b %Y %H:%M:%S", entry["published_parsed"])
135         else:
136             date = ""
137         #text = '''<div style="color: black; background-color: white;">'''
138         text = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>'
139         text = text + '<div><a href=\"' + link + '\">' + title + "</a>"
140         text = text + "<BR /><small><i>Date: " + date + "</i></small></div>"
141         text = text + "<BR /><BR />"
142         text = text + content
143         return text    
144
145
146 class Listing:
147     # Lists all the feeds in a dictionary, and expose the data
148     def __init__(self):
149         self.feeds = {}
150         if isfile(CONFIGDIR+"feeds.pickle"):
151             file = open(CONFIGDIR+"feeds.pickle")
152             self.listOfFeeds = pickle.load(file)
153             file.close()
154         else:
155             self.listOfFeeds = {getId("Slashdot"):{"title":"Slashdot", "url":"http://rss.slashdot.org/Slashdot/slashdot"}, }
156         if self.listOfFeeds.has_key("feedingit-order"):
157             self.sortedKeys = self.listOfFeeds["feedingit-order"]
158         else:
159             self.sortedKeys = self.listOfFeeds.keys()
160             self.sortedKeys.sort(key=lambda obj: self.getFeedTitle(obj))
161         for key in self.sortedKeys:
162             self.loadFeed(key)
163         #self.saveConfig()
164         
165     def loadFeed(self, key):
166             if isfile(CONFIGDIR+key):
167                 file = open(CONFIGDIR+key)
168                 self.feeds[key] = pickle.load(file)
169                 file.close()
170             else:
171                 self.feeds[key] = Feed(self.listOfFeeds[key]["title"], self.listOfFeeds[key]["url"])
172         
173     def updateFeeds(self):
174         for key in self.getListOfFeeds():
175             self.feeds[key].updateFeed()
176             
177     def updateFeed(self, key):
178         self.feeds[key].updateFeed()
179             
180     def getFeed(self, key):
181         return self.feeds[key]
182     
183     def getFeedUpdateTime(self, key):
184         return self.feeds[key].getUpdateTime()
185     
186     def getFeedNumberOfUnreadItems(self, key):
187         return self.feeds[key].getNumberOfUnreadItems()
188    
189     def getFeedTitle(self, key):
190         return self.listOfFeeds[key]["title"]
191     
192     def getFeedUrl(self, key):
193         return self.listOfFeeds[key]["url"]
194     
195     def getListOfFeeds(self):
196         return self.sortedKeys
197     
198     def addFeed(self, title, url):
199         self.listOfFeeds[getId(title)] = {"title":title, "url":url}
200         self.sortedKeys.append(getId(title))
201         self.saveConfig()
202         self.feeds[getId(title)] = Feed(title, url)
203         
204     def removeFeed(self, key):
205         del self.listOfFeeds[key]
206         self.sortedKeys.remove(key)
207         del self.feeds[key]
208         if isfile(CONFIGDIR+key):
209            remove(CONFIGDIR+key)
210     
211     def saveConfig(self):
212         self.listOfFeeds["feedingit-order"] = self.sortedKeys
213         file = open(CONFIGDIR+"feeds.pickle", "w")
214         pickle.dump(self.listOfFeeds, file)
215         file.close()
216         
217     def moveUp(self, key):
218         index = self.sortedKeys.index(key)
219         self.sortedKeys[index] = self.sortedKeys[index-1]
220         self.sortedKeys[index-1] = key
221         
222     def moveDown(self, key):
223         index = self.sortedKeys.index(key)
224         index2 = (index+1)%len(self.sortedKeys)
225         self.sortedKeys[index] = self.sortedKeys[index2]
226         self.sortedKeys[index2] = key