Added read/unread flags for articles
[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.1
23 # Description : PyGtk Example 
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.updateTime = time.asctime()
59            self.entries = tmp["entries"]
60            # Initialize the new articles to unread
61            for index in range(self.getNumberOfEntries()):
62                if not self.readItems.has_key(self.getTitle(index)):
63                    self.countUnread = self.countUnread + 1
64                    self.readItems[self.getTitle(index)] = False
65            del tmp
66            self.saveFeed()
67     
68     def setEntryRead(self, index):
69         if self.readItems[self.getTitle(index)]==False:
70             self.countUnread = self.countUnread - 1
71             self.readItems[self.getTitle(index)] = True
72     
73     def isEntryRead(self, index):
74         return self.readItems[self.getTitle(index)]
75     
76     def getTitle(self, index):
77         return self.entries[index]["title"]
78     
79     def getUpdateTime(self):
80         return self.updateTime
81     
82     def getEntries(self):
83         try:
84             return self.entries
85         except:
86             return []
87     
88     def getNumberOfUnreadItems(self):
89         return self.countUnread
90     
91     def getNumberOfEntries(self):
92         return len(self.entries)
93     
94     def getItem(self, index):
95         try:
96             return self.entries[index]
97         except:
98             return []
99     
100     def getArticle(self, index):
101         self.setEntryRead(index)
102         entry = self.entries[index]
103         title = entry.get('title', 'No title')
104         #content = entry.get('content', entry.get('summary_detail', {}))
105         if entry.has_key('content'):
106             content = entry.content[0].value
107         else:
108             content = entry.get('summary', '')
109         #print content.keys()
110         #.get('value', "No Data")
111         link = entry.get('link', 'NoLink')
112         date = time.strftime("%a, %d %b %Y %H:%M:%S",entry["updated_parsed"])
113         #text = '''<div style="color: black; background-color: white;">'''
114         text = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>'
115         text = text + '<div><a href=\"' + link + '\">' + title + "</a>"
116         text = text + "<BR /><small><i>Date: " + date + "</i></small></div>"
117         text = text + "<BR /><BR />"
118         text = text + content
119         return text    
120
121
122 class Listing:
123     # Lists all the feeds in a dictionary, and expose the data
124     def __init__(self):
125         self.feeds = {}
126         if isfile(CONFIGDIR+"feeds.pickle"):
127             file = open(CONFIGDIR+"feeds.pickle")
128             self.listOfFeeds = pickle.load(file)
129             file.close()
130         else:
131             self.listOfFeeds = {getId("Slashdot"):{"title":"Slashdot", "url":"http://rss.slashdot.org/Slashdot/slashdot"}, }
132         for key in self.listOfFeeds.keys():
133             if isfile(CONFIGDIR+key):
134                 file = open(CONFIGDIR+key)
135                 self.feeds[key] = pickle.load(file)
136                 file.close()
137             else:
138                 self.feeds[key] = Feed(self.listOfFeeds[key]["title"], self.listOfFeeds[key]["url"])
139         self.saveConfig()
140         
141     def updateFeeds(self):
142         for key in self.listOfFeeds.keys():
143             self.feeds[key].updateFeed()
144             
145     def getFeed(self, key):
146         return self.feeds[key]
147     
148     def getFeedUpdateTime(self, key):
149         return self.feeds[key].getUpdateTime()
150     
151     def getFeedNumberOfUnreadItems(self, key):
152         return self.feeds[key].getNumberOfUnreadItems()
153    
154     def getFeedTitle(self, key):
155         return self.listOfFeeds[key]["title"]
156     
157     def getFeedUrl(self, key):
158         return self.listOfFeeds[key]["url"]
159     
160     def getListOfFeeds(self):
161         return self.listOfFeeds.keys()
162     
163     def addFeed(self, title, url):
164         self.listOfFeeds[getId(title)] = {"title":title, "url":url}
165         self.saveConfig()
166         self.feeds[getId(title)] = Feed(title, url)
167         
168     def removeFeed(self, key):
169         del self.listOfFeeds[key]
170         del self.feeds[key]
171         if isfile(CONFIGDIR+key):
172            remove(CONFIGDIR+key)
173     
174     def saveConfig(self):
175         file = open(CONFIGDIR+"feeds.pickle", "w")
176         pickle.dump(self.listOfFeeds, file)
177         file.close()