started with frontend
authorMart Lubbers <mart@martlubbers.net>
Mon, 5 May 2014 11:44:11 +0000 (13:44 +0200)
committerMart Lubbers <mart@martlubbers.net>
Mon, 5 May 2014 11:44:11 +0000 (13:44 +0200)
program/hypfront/feed2html.py [new file with mode: 0644]
program/hypfront/feed2html.pyc [new file with mode: 0644]
program/hypfront/hyper.py [new file with mode: 0644]
program/hypfront/index.html [new file with mode: 0644]
program/hypfront/install.sh [new file with mode: 0644]
program/hypfront/test.html [new file with mode: 0644]

diff --git a/program/hypfront/feed2html.py b/program/hypfront/feed2html.py
new file mode 100644 (file)
index 0000000..436bdc1
--- /dev/null
@@ -0,0 +1,278 @@
+#!/usr/bin/env python
+import sys
+import feedparser
+
+import getopt
+import os
+import re
+import time
+
+DEFAULT_TEMPLATE = """\
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=<tpl:charset filter="xmlq"/>" />
+    <title><tpl:feed value="title" filter="xml" /></title>
+  </head>
+  <body>
+    <div id="container">
+      <h1><a href="<tpl:feed value="link" filter="xmlq"/>"><tpl:feed value="title" filter="xml"/></a></h1>
+      <div id="content">
+        <tpl:entries>
+        <div class="entry">
+          <h3><a href="<tpl:entry value="link" filter="xmlq"/>"><tpl:entry value="title" filter="xml" /></a></h3>
+          <div class="entrybody"><tpl:entry value="summary" /></div>
+          <p class="posted">Posted by <tpl:entry value="author" filter="xml" /> on <tpl:entry value="modified" /></p>
+        </div>
+        </tpl:entries>
+      </div>
+    </div>
+  </body>
+</html>
+"""
+
+class Template:
+    """Generic template library. Initially implemented in bloglines2html.py"""
+    
+    re_parse = re.compile(r'<tpl:(\S+)\b(.*?)(?:/>|>(.*?)</tpl:\1>)', 
+        re.U | re.S)
+    re_parse_attr = re.compile(r'([a-z]+)\s*=\s*"([^"]*)"', re.U|re.I)
+
+    # Default Date/Time format
+    datetime_format = '%Y-%m-%d %H:%M:%S'
+
+    def __init__(self):
+        self.var = {}
+
+    def format_datetime(self, data, format):
+        return time.strftime(format, data)
+
+    def get_charset(self):
+        return 'utf-8'
+
+    def parse(self, text):
+        return self.re_parse.sub(self.process_tag, text)
+
+    def parse_attr(self, text):
+        return dict(self.re_parse_attr.findall(text.strip()))
+
+    def process_tag(self, match):
+        tag  = match.group(1)
+        attr = self.parse_attr(match.group(2))
+        data = match.group(3) or u''
+
+        try:
+            handler = getattr(self, 'tag_%s' % tag)
+        except AttributeError:
+            return ''
+        else:
+            result = handler(attr, data)
+            if result is None:
+                result = ''
+            elif (isinstance(result, tuple) or 
+                    isinstance(result, time.struct_time)) and len(result) == 9:
+                result = self.format_datetime(result, 
+                    attr.get('format', self.datetime_format))
+
+            if 'filter' in attr:
+                result = do_filters(result, attr['filter'])
+            if isinstance(result, unicode):
+                result = result.encode(self.get_charset())
+            else:
+                result = str(result)
+
+            return result
+
+    def tag_charset(self, attr, data):
+        return self.get_charset()
+
+    def tag_var(self, attr, data):
+        # Handle <tpl:var name="foo" />
+        val = self.var.get(attr.get('name'), attr.get('default', ''))
+        if isinstance(val, unicode):
+            val = val.encode(self.get_charset())
+        return val
+
+
+class RSSTemplate(Template):
+    """Template with tag handlers for feed data."""
+
+    re_range = re.compile(r'([\-\d]+)?(:([\-\d]+)?(:([\-\d]+)?)?)?')
+    
+    def __init__(self, feed):
+        Template.__init__(self)
+        self.feed = feed
+        self.content = None
+        self.contributors = None
+        self.enclosures = None
+        self.entries = None
+
+    def get_charset(self):
+        return self.feed.encoding
+
+    def get_loop(self, obj, objattr, attr, data):
+        def range_value(val):
+            if val is None:
+                return val
+            else:
+                return int(val)
+
+        if obj:
+            items = obj.get(objattr)
+            if items:
+                result = []
+                if 'select' in attr:
+                    match = self.re_range.match(attr['select'])
+                    if match:
+                        # Only a single item is selected.
+                        match = [range_value(x) 
+                            for x in list(match.group(1, 3, 5))]
+                        items = items[slice(*match)]
+                        
+                for item in items:
+                    setattr(self, objattr, item)
+                    result.append(self.parse(data))
+
+                setattr(self, objattr, None)
+                return ''.join(result)
+
+        return ''
+
+    def get_value(self, obj, attr, data):
+        if (obj is not None) and ('value' in attr):
+            key = attr['value']
+            detail = attr.get('detail')
+            value = None
+
+            # Check whether it is requesting a datetime field.
+            if (key+'_parsed') in obj:
+                return obj.get(key+'_parsed')
+
+            # Check whether it is trying to get details.
+            if detail:
+                obj2 = attr.get('%s_detail' % key)
+                if obj2:
+                    value = obj2.get(detail)
+            else:
+                value = obj.get(key)
+
+            if isinstance(value, basestring):
+                return value
+
+        return ''
+
+    def tag_content(self, attr, data):
+        return self.get_value(self.content, attr, data)
+
+    def tag_contents(self, attr, data):
+        return self.get_loop(self.entries, 'content', attr, data)
+
+    def tag_contributor(self, attr, data):
+        return self.get_value(self.contributors, attr, data)
+
+    def tag_contributors(self, attr, data):
+        return self.get_loop(self.entries, 'contributors', attr, data)
+
+    def tag_enclosure(self, attr, data):
+        return self.get_value(self.enclosures, attr, data)
+
+    def tag_enclosures(self, attr, data):
+        return self.get_loop(self.entries, 'enclosures', attr, data)
+
+    def tag_entries(self, attr, data):
+        return self.get_loop(self.feed, 'entries', attr, data)
+
+    def tag_entry(self, attr, data):
+        return self.get_value(self.entries, attr, data)
+
+    def tag_feed(self, attr, data):
+        return self.get_value(self.feed.feed, attr, data)
+
+    def tag_if_not(self, attr, data):
+        # Handle <tpl:if_not_tag tag="foo"> ... </tpl:if_not_tag>
+        try:
+            handler = getattr(self, 'tag_%s' % attr['tag'])
+        except (AttributeError, KeyError):
+            pass
+        else:
+            val = handler(attr, data)
+            match = attr.get('match')
+
+            if ((not match) and (not val)) or (match and (val != match)):
+                return self.parse(data)
+
+        return self.parse(data)
+
+    def tag_if(self, attr, data):
+        # Handle <tpl:if_tag tag="foo"> ... </tpl:if_tag>
+        try:
+            handler = getattr(self, 'tag_%s' % attr['tag'])
+        except (AttributeError, KeyError):
+            pass
+        else:
+            val = handler(attr, data)
+            match = attr.get('match')
+
+            if ((not match) and val) or (match and (val == match)):
+                return self.parse(data)
+
+        return ''
+
+    def tag_now(self, attr, data):
+        # Handle <tpl:now format="..." />
+        return time.localtime()
+
+
+def do_filters(data, filters):
+    for f in filters.split(','):
+        f = f.strip()
+
+        # Try to find the filter using the global name space.
+        try:
+            f = globals()['filter_%s' % f]
+        except KeyError:
+            pass
+        else:
+            data = f(data)
+
+    return data
+
+
+def filter_basename(data):
+    """Return the basename of the filename."""
+    idx = data.rfind('/')
+    if idx < 0:
+        idx = data.rfind('\\')
+        if idx < 0:
+            return data
+
+    return data[idx+1:]
+
+
+def filter_reducespace(data):
+    return re.sub(r'[\t\r\n\s]+', ' ', data).strip()
+
+
+def filter_xml(data):
+    """Escape the XML entities."""
+    data = data.replace('&', '&amp;')
+    data = data.replace('<', '&lt;')
+    data = data.replace('>', '&gt;')
+    return data
+
+
+def filter_xmlq(data):
+    """Escape the XML entities + quote, useful for XML attributes."""
+    data = filter_xml(data)
+    data = data.replace('"', '&quot;')
+    return data
+
+
+def rss2html(inp):
+    # Parse the feed data and supply that to RSSTemplate object
+    template = RSSTemplate(inp)
+
+    result = template.parse(DEFAULT_TEMPLATE)
+
+    return result
diff --git a/program/hypfront/feed2html.pyc b/program/hypfront/feed2html.pyc
new file mode 100644 (file)
index 0000000..7c1e6ba
Binary files /dev/null and b/program/hypfront/feed2html.pyc differ
diff --git a/program/hypfront/hyper.py b/program/hypfront/hyper.py
new file mode 100644 (file)
index 0000000..4405580
--- /dev/null
@@ -0,0 +1,40 @@
+#!/bin/env python
+# -*- coding: utf-8 -*-
+
+import feedparser
+import HTMLParser
+import feed2html
+from mod_python import apache
+
+
+def req_pre(req):
+    req.log_error('handler')
+    req.content_type = 'text/html'
+    req.send_http_header()
+    req.write("""<html>
+    <head>
+        <title>HyperFrontend RSS feed input</title>
+    </head>
+    <body>
+""")
+
+
+def req_post(req):
+    req.write("""
+    </body>
+</html>
+""")
+
+
+def handler(req):
+    req_pre(req)
+    args = dict(filter(lambda x: x[1],
+                       map(lambda x: x.split('='),
+                           req.__getattribute__('args').split('&'))))
+    if 'url' not in args and 'name' not in args:
+        req.write('Something went wrong, empty fields?<br />')
+        req.write('<a href="index.html">back</a>')
+    else:
+        req.write(str(args))
+    req_post(req)
+    return apache.OK
diff --git a/program/hypfront/index.html b/program/hypfront/index.html
new file mode 100644 (file)
index 0000000..db11dec
--- /dev/null
@@ -0,0 +1,11 @@
+<html>
+       <body>
+               <form method="get" action="./hyper.py">
+                       <table>
+                               <tr><td><p>RSS URL:  </td><td><input type="text" name="url"></td></tr>
+                               <tr><td><p>RSS Name: </td><td><input type="text" name="name"></td></tr>
+                               <tr><td><input type="submit" value="Submit"</p>
+                       </table>
+               </form>
+       </body>
+</html>
diff --git a/program/hypfront/install.sh b/program/hypfront/install.sh
new file mode 100644 (file)
index 0000000..1cb3451
--- /dev/null
@@ -0,0 +1,3 @@
+sudo rm -v /var/www/py/*
+sudo cp -v ./*.py ./*.html /var/www/py/
+sudo chown -vR www-data:www-data /var/www/py
diff --git a/program/hypfront/test.html b/program/hypfront/test.html
new file mode 100644 (file)
index 0000000..4cdf35b
--- /dev/null
@@ -0,0 +1,136 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+    <title>Nieuw in de voorverkoop Paradiso</title>
+  </head>
+  <body>
+    <div id="container">
+      <h1><a href="http://www.paradiso.nl/web/show/id=178182">Nieuw in de voorverkoop Paradiso</a></h1>
+      <div id="content">
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Dondergrondse-Fuck-Forever-band-night.htm">donderdag 26 juni 2014 23:30 - Dondergrondse: Fuck Forever band night</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Dondergrondse-18.htm">donderdag 19 juni 2014 23:30 - Dondergrondse</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Kina-Grannis-Locatie-Bitterzoet.htm">zaterdag 7 juni 2014 20:00 - Kina Grannis - Locatie: Bitterzoet</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Jay-Brannan.htm">vrijdag 3 oktober 2014 19:30 - Jay Brannan</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Dondergrondse-hosted-by-The-Daily-Indie-Live-The-Futures-Dust.htm">donderdag 12 juni 2014 23:30 - Dondergrondse: hosted by The Daily Indie – Live: The Future’s Dust</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Blitz-Kids.htm">woensdag 23 juli 2014 20:00 - Blitz Kids</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Noodlanding-301.htm">donderdag 26 juni 2014 23:30 - Noodlanding!</a></h3>
+          <div class="entrybody">Dansnacht, alternatieve hits</div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Noodlanding-300.htm">donderdag 19 juni 2014 23:30 - Noodlanding!</a></h3>
+          <div class="entrybody">Dansnacht, alternatieve hits</div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Natural-Child-3VOOR12-presents-Locatie-Tolhuistuin-zaal.htm">maandag 15 september 2014 19:30 - Natural Child – 3VOOR12 presents   -   Locatie: Tolhuistuin (zaal)</a></h3>
+          <div class="entrybody">aftrap officiële openingsweek van nieuwe zaal Tolhuistuin</div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Ben-Miller-Band.htm">zaterdag 5 juli 2014 22:00 - Ben Miller Band</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Zoot-Woman-ADE-Locatie-Tolhuistuin-zaal.htm">donderdag 16 oktober 2014 20:30 - Zoot Woman – ADE   -   Locatie: Tolhuistuin (zaal)</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Little-Barrie-Locatie-Bitterzoet.htm">woensdag 25 juni 2014 21:00 - Little Barrie   -   Locatie: Bitterzoet</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Earth-Wind-Fire-Experience-feat.-Al-McKay.htm">woensdag 3 september 2014 19:30 - Earth Wind &amp; Fire Experience feat. Al McKay</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Direct-2.htm">zondag 19 oktober 2014 19:00 - Di-rect</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Royal-Wood.htm">vrijdag 10 oktober 2014 19:30 - Royal Wood</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Dark-Alley-Cabaret.htm">zondag 1 juni 2014 20:00 - Dark Alley Cabaret</a></h3>
+          <div class="entrybody">Amsterdam Burlesque Weekend</div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/The-News-Reality-Opera-van-Jacob-TV-door-de-Nederlandse-Reisopera.htm">maandag 2 juni 2014 20:30 - The News – Reality Opera van Jacob TV door de Nederlandse Reisopera</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Wij-zijn-18-filmpremiere-Palio-Superspeed-Donkey-afterparty.htm">zaterdag 24 mei 2014 21:00 - ‘Wij zijn 18’: filmpremiere, Palio Superspeed Donkey &amp; afterparty</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Wiz-Khalifa.htm">maandag 30 juni 2014 20:30 - Wiz Khalifa</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+        <div class="entry">
+          <h3><a href="http://www.paradiso.nl/web/Agenda-Item/Dave-Hause-Locatie-Bitterzoet.htm">woensdag 20 augustus 2014 21:00 - Dave Hause   -   Locatie: Bitterzoet</a></h3>
+          <div class="entrybody"></div>
+          <p class="posted">Posted by  on </p>
+        </div>
+        
+      </div>
+      <div id="footer">Generated on 2014-05-05 13:23:47 by <a href="http://scott.yang.id.au/project/feed2html">Feed2HTML 1.0</a></div>
+    </div>
+  </body>
+</html>