gem

a fork of khuxkm's gemini to web proxy
Log | Files | Refs

gem2html.py (3419B)


      1 import random, functools, os
      2 from html import escape
      3 
      4 _rand_n = lambda: functools.reduce(lambda x, y: (x<<8)+y,os.urandom(4))
      5 
      6 ALPHABET = "0123456789abcdefghijklmnopqrstuvwxyz"
      7 USED_IDS = set()
      8 def rand_id():
      9     n = _rand_n()
     10     id = ""
     11     while n>0:
     12         n, index = divmod(n,len(ALPHABET))
     13         id = ALPHABET[index]+id
     14     if id in USED_IDS: return rand_id()
     15     return id
     16 
     17 def gem2html(content,link_callback=lambda url, text: (url, text)):
     18     lines = content.splitlines()
     19     out = """<!DOCTYPE html>
     20 <html>
     21 <head>
     22   <meta charset="UTF-8">
     23   <meta name="viewport" content="width=device-width, initial-scale=1">
     24   <link rel="stylesheet" href="gem.css"></head>
     25 <body>
     26 
     27         """
     28     pre = False
     29     pre_alt = False
     30     set_title = False
     31     for line in lines:
     32         if pre:
     33             if line[:3]=="```":
     34                 pre=False
     35                 out+="</pre>\n"
     36                 if pre_alt:
     37                     out+="</figure>\n"
     38                     pre_alt=False
     39             else:
     40                 out+=escape(line)+"\n"
     41         else:
     42             if line[:3]=="```":
     43                 if len(line)>3:
     44                     cap_id = rand_id()
     45                     out+="<figure role='img' aria-captionedby='{0}'><figcaption id='{0}' style='clip: rect(0 0 0 0); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px;'>{1}</figcaption>\n".format(cap_id,escape(line[3:]))
     46                     pre_alt = True
     47                 pre = True
     48                 out+="<pre>\n"
     49             elif line.startswith("#"):
     50                 if line[:3]=="###":
     51                     out+="<h3>{}</h3>".format(escape(line[3:].strip()))
     52                 elif line[:2]=="##":
     53                     out+="<h2>{}</h2>".format(escape(line[2:].strip()))
     54                 elif line[:1]=="#":
     55                     out+="<h1>{}</h1>".format(escape(line[1:].strip()))
     56                     if not set_title:
     57                         out+="<title>{}</title>".format(escape(line[1:].strip()))
     58                         set_title = True
     59             elif line.startswith("* "):
     60                 out += "<ul>\n<li>{}</li>\n</ul>\n".format(escape(line[1:].strip()))
     61                 # combine consecutive unordered list items into one unordered list
     62                 out = out.replace("</ul>\n<ul>\n","")
     63             elif line.startswith("=>"):
     64                 parts = line.split(None,2)
     65                 try:
     66                     url, text = parts[1:]
     67                 except ValueError:
     68                     try:
     69                         url=parts[1]
     70                         text=parts[1]
     71                     except:
     72                         # no link content at all
     73                         # just put a literal => in there
     74                         out+="<p></p>".format(escape(parts[0]))
     75                         continue
     76                 # now comes the fun part, use the link callback to mutilate these
     77                 url, text = link_callback(url, text)
     78                 # and now render
     79                 out+="<p><a href='{}'>{}</a></p>".format(escape(url),escape(text))
     80             elif line.startswith(">"):
     81                 out+="<blockquote><p>{}</p></blockquote>".format(escape(line))
     82             else: # any other line is a text line
     83                 if line:
     84                     out+="<p>{}</p>".format(escape(line))
     85                 else:
     86                     out+="<p><br></p>"
     87     out+="</body>"
     88     return out