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