feedgenerator

A simple tool to create various feeds
git clone https://git.ortlepp.eu/feedgenerator.git/
Log | Files | Refs | README | LICENSE

common.py (6100B)


      1 # -*- coding: utf-8 -*-
      2 
      3 import hashlib
      4 import html
      5 import pathlib
      6 import configparser
      7 
      8 try:
      9     import zoneinfo
     10 except ImportError:
     11     from backports import zoneinfo
     12 
     13 
     14 # This class is a singleton, see https://en.wikipedia.org/wiki/Singleton_pattern#Python
     15 class Config:
     16     __INSTANCE = None
     17 
     18     __WORK_DIR = ""
     19 
     20     __CONFIG = configparser.ConfigParser()
     21 
     22     def __new__(self, *args):
     23         if self.__INSTANCE is None:
     24             self.__INSTANCE = object.__new__(self, *args)
     25         return self.__INSTANCE
     26 
     27     def __init__(self):
     28         self.__WORK_DIR = str(pathlib.Path(__file__).parent.resolve())
     29         if self.__WORK_DIR.endswith(".pyz"):
     30             self.__WORK_DIR = str(pathlib.Path(__file__).parent.resolve().parent)
     31         self.__CONFIG.read(self.get_workdir() + "/feedgenerator.ini", encoding="utf-8")
     32 
     33     def get_workdir(self):
     34         return self.__WORK_DIR
     35 
     36     def get_database(self):
     37         return self.__WORK_DIR + "/feedgenerator.sqlite"
     38 
     39     def get_antennemuenster_filename(self):
     40         return self.__CONFIG.get("AntenneMuensterFeed", "filename", fallback="antenne_muenster.xml")
     41 
     42     def get_antennemuenster_file(self):
     43         return self.get_workdir() + "/" + self.get_antennemuenster_filename()
     44 
     45     def get_antennemuenster_items(self):
     46         return self.__CONFIG.getint("AntenneMuensterFeed", "items", fallback=10)
     47 
     48     def get_deutschlandfunk_filename(self):
     49         return self.__CONFIG.get("DeutschlandfunkFeed", "filename", fallback="deutschlandfunk.xml")
     50 
     51     def get_deutschlandfunk_file(self):
     52         return self.get_workdir() + "/" + self.get_deutschlandfunk_filename()
     53 
     54     def get_deutschlandfunk_items(self):
     55         return self.__CONFIG.getint("DeutschlandfunkFeed", "items", fallback=10)
     56 
     57     def get_deutschlandfunk_ignoretopics(self):
     58         return self.__CONFIG.get("DeutschlandfunkFeed", "ignore_topics", fallback="").split("|")
     59 
     60     def get_heise_filename(self):
     61         return self.__CONFIG.get("HeiseFeed", "filename", fallback="heise.xml")
     62 
     63     def get_heise_file(self):
     64         return self.get_workdir() + "/" + self.get_heise_filename()
     65 
     66     def get_heise_items(self):
     67         return self.__CONFIG.getint("HeiseFeed", "items", fallback=10)
     68 
     69     def get_heise_ignoretitle(self):
     70         return self.__CONFIG.get("HeiseFeed", "ignore_title", fallback="").split("|")
     71 
     72     def get_heise_ignoreurl(self):
     73         return self.__CONFIG.get("HeiseFeed", "ignore_url", fallback="").split("|")
     74 
     75 
     76 
     77 class FeedItem:
     78 
     79     def __init__(self, title, date, author, content, url):
     80         self.__title = title
     81         self.__date = date
     82         self.__author = author
     83         self.__content = content
     84         self.__url = url
     85 
     86     def __str__(self):
     87         return self.__title + " (" + str(self.__date) + ")"
     88 
     89     def get_title(self):
     90         return self.__title
     91 
     92     def get_date(self):
     93         return self.__date
     94 
     95     def get_author(self):
     96         return self.__author
     97 
     98     def get_content(self):
     99         return self.__content
    100 
    101     def get_url(self):
    102         return self.__url
    103 
    104 
    105 
    106 class AtomFeed:
    107 
    108     def __init__(self, title, author, baseurl, updated, icon, logo):
    109         self.__title = title
    110         self.__author = author
    111         self.__baseurl = baseurl
    112         self.__updated = updated
    113         self.__icon = icon
    114         self.__logo = logo
    115         self.__items = []
    116 
    117 
    118     def __format_datetime(self, datetime):
    119         utc_datetime = datetime.astimezone(zoneinfo.ZoneInfo('UTC'))
    120         return utc_datetime.isoformat()
    121 
    122 
    123     def __create_element(self, *args):
    124         if len(args) == 2:
    125             return "<{0}>{1}</{0}>\n".format(args[0], args[1])
    126         elif len(args) == 3:
    127             return "<{0} {1}=\"{2}\" />\n".format(args[0], args[1], args[2])
    128         elif len(args) == 4:
    129             return "<{0} {1}=\"{2}\">{3}</{0}>\n".format(args[0], args[2], args[3], args[1])
    130         else:
    131             return ""
    132 
    133 
    134     def __feed_item(self, item):
    135         atom_title = self.__create_element("title", item.get_title())
    136         atom_link = self.__create_element("link", "href", item.get_url())
    137         atom_id = self.__create_element("id", "urn:uuid:" + hashlib.sha256(item.get_title().lower().encode()).hexdigest())
    138         atom_author = self.__create_element("author", self.__create_element("name", item.get_author()))
    139         atom_updated = self.__create_element("updated", self.__format_datetime(item.get_date()))
    140         atom_content = self.__create_element("content", html.escape(item.get_content()), "type", "html")
    141         return self.__create_element("entry", atom_title + atom_link + atom_id + atom_author + atom_updated + atom_content)
    142 
    143 
    144     def add_item(self, item):
    145         self.__items.append(item)
    146 
    147 
    148     def get_item(self, index):
    149         return self.__items[index]
    150 
    151 
    152     def set_updated(self, updated):
    153         self.__updated = updated
    154 
    155 
    156     def write_feed(self, feedfile):
    157         atom_title = self.__create_element("title", self.__title)
    158         atom_link = self.__create_element("link", "href", self.__baseurl)
    159         atom_id = self.__create_element("id", "urn:uuid:" + hashlib.sha256(self.__baseurl.encode()).hexdigest())
    160         atom_author = self.__create_element("author", self.__create_element("name", self.__author))
    161         atom_updated = self.__create_element("updated", self.__format_datetime(self.__updated))
    162         atom_icon = self.__create_element("icon", self.__icon)
    163         atom_logo = self.__create_element("logo", self.__logo)
    164 
    165         try:
    166             with open(feedfile, "w", encoding="utf-8") as file:
    167                 file.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
    168                 file.write("<feed xmlns=\"http://www.w3.org/2005/Atom\">\n")
    169                 file.write(atom_title + atom_link + atom_id + atom_author + atom_updated + atom_icon + atom_logo)
    170                 for item in self.__items:
    171                     file.write(self.__feed_item(item))
    172                     self.__format_datetime(item.get_date())
    173                 file.write("</feed>\n")
    174         except PermissionError:
    175             print("No permission to write " + feedfile)
    176             return False
    177 
    178         return True