always load the local configuration file
[enigma2-curlytx.git] / src / AtomFeed.py
1 # -*- coding: utf-8 -*-
2 # CurlyTx Atom feed parser
3 # Copyright (C) 2011 Christian Weiske <cweiske@cweiske.de>
4 # License: GPLv3 or later
5
6 from twisted.web.client import getPage
7 from xml.etree.cElementTree import fromstring, ParseError
8
9 import os
10
11 class AtomFeed:
12     """ Simple XML parser that extracts pages from a atom feed """
13     ns = "{http://www.w3.org/2005/Atom}"
14     errorCallback = None
15
16     def __init__(self, url, callback, errorCallback):
17         """ Fetches the URL
18
19         Parsed pages are sent back to callback by parse()
20         """
21         self.errorCallback = errorCallback
22         if (url.startswith('file://')):
23             file = url[7:]
24             if not os.path.exists(file):
25                 errorCallback('Settings atom feed file does not exist: ' + file)
26                 return
27
28             with open(file, 'r') as f:
29                 self.parse(f.read(), callback)
30         else:
31             getPage(url).addCallback(self.parse, callback).addErrback(self.onError)
32
33     def parse(self, data, callback):
34         """ Parse atom feed data into pages list and run callback """
35         try:
36             xml = fromstring(data)
37         except ParseError:
38             return self.errorCallback("Invalid XML")
39
40         pages = []
41         for entry in xml.findall("{0}entry".format(self.ns)):
42             titleE = entry.find("{0}title".format(self.ns))
43             url   = self.bestLink(entry.findall("{0}link".format(self.ns)))
44             if titleE != None and titleE.text != "" and url != None:
45                 pages.append({"title": titleE.text, "url": url})
46
47         callback(pages)
48
49     def bestLink(self, list):
50         """ Fetch the best matching link from an atom feed entry """
51         foundLevel = -1
52         foundHref = None
53         for link in list:
54             if link.get("rel") != "alternate" and link.get("rel") != "":
55                 continue
56             level = self.level(link)
57             if foundLevel > level:
58                 continue
59             foundLevel = level
60             foundHref = link.get("href")
61         return foundHref
62
63     def level(self, link):
64         """ Determines the level of a link
65
66         "text/plain" type links are best, links without type are second.
67         All others have the lowest level 1.
68         """
69         type = link.get("type")
70         if type == "text/plain":
71             return 3
72         elif type == "":
73             return 2
74         return 1
75
76     def onError(self, error):
77         """ Pass the error message only """
78         self.errorCallback(error.getErrorMessage())