feeddb.py - zs - Zeitungsschau rss to email converter
 (HTM) git clone git://r-36.net/zs
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       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