| ---
feeddb.py (6332B)
---
1 #
2 # See LICENSE for licensing details.
3 #
4 # Copy me if you can.
5 # by 20h
6 #
7
8 import pickle
9 import os
10 import os.path
11 import fcntl
12 from subprocess import Popen
13
14 class feeddb(object):
15 feeds = {}
16 cfg = {}
17 dbpath = ""
18 lpath = ""
19 lockarr = ""
20 locks = {}
21 default = True
22
23 def lock(self, fpath):
24 if fpath not in self.locks:
25 self.lpath = "%s.lck" % (fpath)
26 self.locks[fpath] = open(self.lpath, "w")
27 fcntl.lockf(self.locks[fpath].fileno(), fcntl.LOCK_EX)
28
29 def unlock(self, fpath, doremove=True):
30 if fpath in self.locks:
31 fcntl.flock(self.locks[fpath].fileno(), fcntl.LOCK_UN)
32 self.locks[fpath].close()
33 lpath = "%s.lck" % (fpath)
34 try:
35 os.remove(lpath)
36 except FileNotFoundError:
37 pass
38 if doremove == True:
39 del self.locks[fpath]
40
41 def pickleread(self, fi):
42 fpath = "%s/%s" % (self.dbpath, fi)
43 path = os.path.abspath(os.path.dirname(fpath))
44 if not os.path.exists(path):
45 os.makedirs(path, 0o750)
46
47 self.lock(fpath)
48
49 try:
50 fd = open(fpath, "rb")
51 db = pickle.load(fd)
52 fd.close()
53 except FileNotFoundError:
54 db = {}
55
56 return db
57
58 def picklewrite(self, fi, db):
59 fpath = "%s/%s" % (self.dbpath, fi)
60 path = os.path.abspath(os.path.dirname(fpath))
61 if not os.path.exists(path):
62 os.makedirs(path, 0o750)
63
64 fd = open(fpath, "wb+")
65 pickle.dump(db, fd)
66 fd.close()
67
68 def unlockall(self):
69 for key in self.locks.keys():
70 self.unlock(key, doremove=False)
71 self.locks = []
72
73 def __init__(self, path="~/.zs", email=None):
74 self.dbpath = os.path.abspath(os.path.expanduser(path))
75 self.feeds = self.pickleread("feeds.db")
76 self.cfg = self.pickleread("cfg.db")
77
78 if not "email" in self.cfg:
79 print("You need to specify the default email. Please "\
80 "run 'zs cfg email me@me.com' to "\
81 "set it.")
82 else:
83 self.default = False
84
85 if not "smtphost" in self.cfg:
86 self.cfg["smtphost"] = "localhost"
87 if not "smtpport" in self.cfg:
88 self.cfg["smtpport"] = None
89 if not "smtpssl" in self.cfg:
90 self.cfg["smtpssl"] = "False"
91 if not "smtpuser" in self.cfg:
92 self.cfg["smtpuser"] = None
93 if not "smtppassword" in self.cfg:
94 self.cfg["smtppassword"] = None
95 if not "smtpstarttls" in self.cfg:
96 self.cfg["smtpstarttls"] = "False"
97 if not "smtpcmd" in self.cfg:
98 self.cfg["smtpcmd"] = None
99 if not "smtpuselocal" in self.cfg:
100 self.cfg["smtpuselocal"] = "False"
101
102 def sync(self):
103 if self.cfg != None and self.default == False:
104 self.picklewrite("cfg.db", self.cfg)
105 if self.feeds != None and self.default == False:
106 self.picklewrite("feeds.db", self.feeds)
107
108 def __del__(self):
109 self.sync()
110 self.unlockall()
111
112 def readfeed(self, uri):
113 if not uri in self.feeds:
114 return None
115 return self.feeds[uri]
116
117 def writefeed(self, uri, feed):
118 self.feeds[uri] = feed
119 self.default = False
120
121 def sethook(self, uri, hookfile):
122 feed = self.readfeed(uri)
123 if feed == None:
124 return
125 feed["hook"] = hookfile
126 self.writefeed(uri, feed)
127
128 def runhook(self, uri):
129 feed = self.readfeed(uri)
130 if feed == None:
131 return
132 if not "hook" in feed:
133 return
134
135 cmd = os.path.expanduser(feed["hook"])
136 if not os.path.exists(cmd):
137 return
138
139 fd = open("/dev/null")
140 if os.fork() == 0:
141 p = Popen(cmd, shell=True, stdout=fd, stderr=fd)
142 p.wait()
143
144 def setfeedval(self, uri, key, value):
145 feed = self.readfeed(uri)
146 if feed == None:
147 return
148 feed[key] = value
149 self.writefeed(uri, feed)
150
151 def getfeedval(self, uri, key):
152 feed = self.readfeed(uri)
153 if feed == None:
154 return None
155 if key not in feed:
156 return None
157 return feed[key]
158
159 def setretry(self, uri, retries):
160 self.setfeedval(uri, "retry", retries)
161
162 def getretry(self, uri):
163 retries = self.getfeedval(uri, "retry")
164 if retries == None:
165 return 0
166 else:
167 return retries
168
169 def pause(self, uri):
170 self.setfeedval(uri, "pause", True)
171
172 def unpause(self, uri):
173 self.setfeedval(uri, "pause", False)
174 self.setretry(uri, 0)
175
176 def ispaused(self, uri):
177 return self.getfeedval(uri, "pause")
178
179 def listfeeds(self):
180 return list(self.feeds.keys())
181
182 def addfeed(self, uri):
183 if not uri in self.listfeeds():
184 feed = {}
185 feed["uri"] = uri
186 feed["pause"] = False
187 feed["articles"] = []
188 self.writefeed(uri, feed)
189 self.default = False
190
191 def delfeed(self, uri):
192 if uri in self.listfeeds():
193 del self.feeds[uri]
194 return True
195 else:
196 return False
197
198 def listactivefeeds(self):
199 rfeeds = []
200 for f in self.feeds:
201 if self.feeds[f]["pause"] == False:
202 rfeeds.append(f)
203 return rfeeds
204
205 def mergefeed(self, uri, curfeed):
206 rarticles = []
207 feed = self.readfeed(uri)
208 if feed == None:
209 return curfeed
210
211 history = feed["articles"]
212 for article in curfeed["articles"]:
213 a = [art for art in history if art["uuid"] == \
214 article["uuid"]]
215 if len(a) == 0:
216 article["unread"] = True
217 history.append(article)
218 rarticles.append(article)
219 # Only keep track of the last 2048 articles.
220 feed["articles"] = history[-2048:]
221
222 for metakey in ("link", "title", "updated", "author", \
223 "email", "feeduri"):
224 if metakey in curfeed:
225 feed[metakey] = curfeed[metakey]
226
227 self.writefeed(uri, feed)
228 curfeed["articles"] = rarticles
229
230 return curfeed
231
232 def unreadarticles(self, uri):
233 rfeed = {}
234 rfeed["articles"] = []
235 feed = self.readfeed(uri)
236 if feed == None:
237 return rfeed
238
239 for metakey in ("link", "title", "updated", "author", \
240 "email", "toemail", "feeduri"):
241 if metakey in feed:
242 rfeed[metakey] = feed[metakey]
243
244 history = feed["articles"]
245 for article in history:
246 if article["unread"] == True:
247 rfeed["articles"].append(article)
248
249 return rfeed
250
251 def setarticleunread(self, uri, ids):
252 feed = self.readfeed(uri)
253 if feed == None:
254 return
255
256 for article in feed["articles"]:
257 a = [art for art in feed["articles"] if art["uuid"] == \
258 ids]
259 if len(a) > 0:
260 for aa in a:
261 aa["unread"] = True
262 self.writefeed(uri, feed);
263
264 def setreadarticles(self, uri, curfeed=None):
265 feed = self.readfeed(uri)
266 if feed == None:
267 return
268
269 for article in curfeed["articles"]:
270 a = [art for art in curfeed["articles"] if art["uuid"] == \
271 article["uuid"]]
272 if len(a) > 0:
273 for aa in a:
274 aa["unread"] = False
275 self.writefeed(uri, feed);
276
277 def resetarticles(self, uri):
278 feed = self.readfeed(uri)
279 if feed == None:
280 return
281 feed["articles"] = []
282 self.writefeed(uri, feed)
283 |