From 975b9912bc41c5361f41ac53dc318024a931f749 Mon Sep 17 00:00:00 2001 From: manetta Date: Wed, 12 Jan 2022 21:27:06 +0100 Subject: [PATCH] bending pad2pdf into octomode --- Makefile | 9 + octomode.py | 213 ++++++++++++++++++ requirements.txt | 5 +- start.py | 58 ----- static/interface.css | 180 --------------- static/main.css | 82 ++++++- templates/base.html | 42 +++- templates/default-pandoc-template.html | 32 +++ templates/default.css | 10 + templates/default.md | 6 + templates/html.html | 2 +- templates/{stylesheet.html => index.html} | 2 - templates/pad.html | 2 +- templates/pagedjs.html | 5 - ...late-pagedjs.html => pandoc-template.html} | 8 +- templates/pdf.html | 30 +++ templates/start.html | 13 ++ 17 files changed, 428 insertions(+), 271 deletions(-) create mode 100644 Makefile create mode 100755 octomode.py delete mode 100755 start.py delete mode 100644 static/interface.css create mode 100644 templates/default-pandoc-template.html create mode 100644 templates/default.css create mode 100644 templates/default.md rename templates/{stylesheet.html => index.html} (51%) delete mode 100644 templates/pagedjs.html rename templates/{pandoc-template-pagedjs.html => pandoc-template.html} (71%) create mode 100644 templates/pdf.html create mode 100644 templates/start.html diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2fe9b05 --- /dev/null +++ b/Makefile @@ -0,0 +1,9 @@ +default: run + +setup: + @python3 -m venv .venv + @.venv/bin/pip install -r requirements.txt + +run: + @.venv/bin/python octomode.py + diff --git a/octomode.py b/octomode.py new file mode 100755 index 0000000..f34956e --- /dev/null +++ b/octomode.py @@ -0,0 +1,213 @@ +import flask +from flask import request +from urllib.request import urlopen +from urllib.parse import urlencode +import json +import os +import pypandoc +from jinja2 import Template + +APP = flask.Flask(__name__) +APP.config.from_object("config.Config") + +# --- + +def get_pad_content(pad): + arguments = { + 'padID' : pad, + 'apikey' : APP.config['PAD_API_KEY'] + } + api_call = 'getText' + response = json.load(urlopen(f"{ APP.config['PAD_API_URL'] }{ api_call }", data=urlencode(arguments).encode())) + + # create pad in case it does not yet exist + if response['code'] == 1 and 'padID does not exist' == response['message']: + api_call = 'createPad' + urlopen(f"{ APP.config['PAD_API_URL'] }{ api_call }", data=urlencode(arguments).encode()) + api_call = 'getText' + response = json.load(urlopen(f"{ APP.config['PAD_API_URL'] }{ api_call }", data=urlencode(arguments).encode())) + + # print(response) + content = response['data']['text'] + return content + +def all_pads(): + arguments = { + 'apikey' : APP.config['PAD_API_KEY'], + } + api_call = 'listAllPads' + response = json.load(urlopen(f"{ APP.config['PAD_API_URL'] }{ api_call }", data=urlencode(arguments).encode())) + + return response + +def create_pad_on_first_run(name, ext): + pads = all_pads() + pad = name+ext + + if 'md' in ext: + default_template = 'templates/default.md' + elif 'css' in ext: + default_template = 'templates/default.css' + elif 'template' in ext: + default_template = 'templates/default-pandoc-template.html' + + if 'template' in ext: + default_template = open(default_template).read() + jinja_template = Template(default_template) + default_template = jinja_template.render(name=name.strip()) + else: + default_template = open(default_template).read() + + if pad not in pads['data']['padIDs']: + arguments = { + 'padID' : pad, + 'apikey' : APP.config['PAD_API_KEY'], + 'text' : default_template + } + api_call = 'createPad' + response = json.load(urlopen(f"{ APP.config['PAD_API_URL'] }{ api_call }", data=urlencode(arguments).encode())) + +def update_pad_contents(name): + # download the md pad + stylesheet + template pad + md_pad = f'{ name }.md' + css_pad = f'{ name }.css' + template_pad = f'{ name }.template' + md = get_pad_content(md_pad) + css = get_pad_content(css_pad) + template = get_pad_content(template_pad) + # !!! this breaks the whole idea that this application can be shared by multiple projects at the same time + # !!! but py_pandoc needs to run with files........ hmmm + with open('templates/pandoc-template.html', 'w') as f: + f.write(template) + + return md, css, template + +# --- + +@APP.route('/', methods=['GET', 'POST']) +def index(): + name = request.values.get('name') + if name: + # This is when the environment is "created" + # The pads are filled with the default templates (pad, stylesheet, template) + exts = ['.md', '.css', '.template'] + for ext in exts: + create_pad_on_first_run(name, ext) + return flask.redirect(f'/{ name }/') + else: + return flask.render_template('start.html') + +@APP.route('//', methods=['GET']) +def main(name): + # !!! Add a if/else here to check if the environment is "created" already + ext = '.md' + create_pad_on_first_run(name, ext) + return flask.render_template('pad.html', name=name.strip(), ext=ext) + +@APP.route('//pad/') +def pad(name): + ext = '.md' + create_pad_on_first_run(name, ext) + return flask.render_template('pad.html', name=name.strip(), ext=ext) + +@APP.route('//stylesheet/', methods=['GET']) +def stylesheet(name): + ext = '.css' + create_pad_on_first_run(name, ext) + return flask.render_template('pad.html', name=name.strip(), ext=ext) + +@APP.route('//template/', methods=['GET']) +def template(name): + ext = '.template' + create_pad_on_first_run(name, ext) + return flask.render_template('pad.html', name=name.strip(), ext=ext) + +# @APP.route('//html/') +# def html(name): +# # update pad contents +# md, css, template = update_pad_contents(name) +# # generate html page +# pandoc_args = [ +# # '--css=static/print.css', +# '--toc', +# '--toc-depth=1', +# '--template=templates/pandoc-template.html', +# '--standalone' +# ] +# html = pypandoc.convert_text(md, 'html', format='md', extra_args=pandoc_args) + +# return flask.render_template('html.html', html=html, name=name.strip()) + +@APP.route('//pdf/') +def pdf(name): + # In case the URL is edited directly with a new name + exts = ['.md', '.css', '.template'] + for ext in exts: + create_pad_on_first_run(name, ext) + return flask.render_template('pdf.html', name=name.strip()) + +# ////////////// +# rendered resources (not saved as a file on the server) + +@APP.route('//print.css') +def css(name): + x, css, x = update_pad_contents(name) + + return css, 200, {'Content-Type': 'text/css; charset=utf-8'} + +@APP.route('//pandoc-template.html') +def pandoc_template(name): + x, x, template = update_pad_contents(name) + + return template, 200, {'Content-Type': 'text/html; charset=utf-8'} + +@APP.route('//pagedjs.html') +def pagedjs(name): + # update pad contents + md, css, template = update_pad_contents(name) + # generate html page with the pandoc template (with paged.js inserted in the header) + pandoc_args = [ + '--toc', + '--toc-depth=1', + '--template=templates/pandoc-template.html', + '--standalone' + ] + html = pypandoc.convert_text(md, 'html', format='md', extra_args=pandoc_args) + + return html, 200, {'Content-Type': 'text/html; charset=utf-8'} + +# ////////////// + +def flask_logger(): + # creates logging information + # https://www.vantage-ai.com/en/blog/adding-on-screen-logging-in-a-few-steps-using-a-flask-application + + from io import StringIO + import logging + from time import sleep + + log_stream = StringIO() + handler = logging.StreamHandler(log_stream) + log = logging.getLogger('werkzeug') + log.setLevel(logging.DEBUG) + log.addHandler(handler) + + while True: + yield log_stream.getvalue() + # "flush" the stream, move the seek/truncate points to 0 + log_stream.seek(0) + log_stream.truncate(0) + + sleep(0.1) + +@APP.route('/log/', methods=['GET']) +def log(): + # returns logging information + return flask.Response(flask_logger(), mimetype="text/plain", content_type="text/event-stream") + +# ///////////// + + +if __name__ == '__main__': + APP.debug=True + APP.run(host="0.0.0.0", port=f'{ APP.config["PORTNUMBER"] }', threaded=True) diff --git a/requirements.txt b/requirements.txt index 40257c7..f4480ca 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,6 @@ flask -etherpump markdown +urllib3 +pandoc +pypandoc +jinja \ No newline at end of file diff --git a/start.py b/start.py deleted file mode 100755 index c90fe5e..0000000 --- a/start.py +++ /dev/null @@ -1,58 +0,0 @@ -import flask -from flask import request -import urllib, json -import os - -# Create the application. -APP = flask.Flask(__name__) - -# --- - -#The following three lines are the variables that need to be changed when making a new project. - -PROJECTNAME = 'dsn' -DIR_PATH = '/home/systers/dsn-documentation' -PORTNUMBER = 5123 - -# --- - - -pads = [ - f'{ PROJECTNAME }.md', - f'{ PROJECTNAME }.css' - ] - -def download(pads): - # using etherpump - for pad in pads: - os.system(f'{ DIR_PATH }/venv/bin/etherpump gettext { pad } > { DIR_PATH }/static/{ pad }') - -@APP.route('/', methods=['GET']) -def pad(): - return flask.render_template('pad.html') - -@APP.route('/pagedjs/', methods=['GET', 'POST']) -def pagedjs(): - # download the main post-script pad + stylesheet pad - download(pads) - # generate html page with the pandoc template (with paged.js inserted in the header) - os.system(f'pandoc -f markdown -t html -c { PROJECTNAME }.css --toc --toc-depth=1 --template { DIR_PATH }/templates/pandoc-template-pagedjs.html --standalone { DIR_PATH }/static/{ PROJECTNAME }.md -o { DIR_PATH }/static/{ PROJECTNAME }.pagedjs.html') - - return flask.render_template('pagedjs.html') - -@APP.route('/html/', methods=['GET', 'POST']) -def html(): - # download the main post-script pad + stylesheet pad - download(pads) - # generate html page - os.system(f'pandoc -f markdown -t html -c { PROJECTNAME }.css --toc --toc-depth=1 --standalone { DIR_PATH }/static/{ PROJECTNAME }.md -o { DIR_PATH }/static/{ PROJECTNAME }.html') - - return flask.render_template('html.html') - -@APP.route('/stylesheet/', methods=['GET']) -def stylesheet(): - return flask.render_template('stylesheet.html') - -if __name__ == '__main__': - APP.debug=True - APP.run(port=f'{ PORTNUMBER }') diff --git a/static/interface.css b/static/interface.css deleted file mode 100644 index ff30f68..0000000 --- a/static/interface.css +++ /dev/null @@ -1,180 +0,0 @@ -/* CSS for Paged.js interface – v0.2 */ - -/* Change the look */ -:root { - --color-background: whitesmoke; - --color-pageSheet: #cfcfcf; - --color-pageBox: violet; - --color-paper: white; - --color-marginBox: transparent; - --pagedjs-crop-color: black; - --pagedjs-crop-shadow: white; - --pagedjs-crop-stroke: 1px; -} - -/* To define how the book look on the screen: */ -@media screen { - body { - background-color: var(--color-background); - } - - .pagedjs_pages { - display: flex; - width: calc(var(--pagedjs-width) * 2); - flex: 0; - flex-wrap: wrap; - margin: 0 auto; - } - - .pagedjs_page { - background-color: var(--color-paper); - box-shadow: 0 0 0 1px var(--color-pageSheet); - margin: 0; - flex-shrink: 0; - flex-grow: 0; - margin-top: 10mm; - } - - .pagedjs_first_page { - margin-left: var(--pagedjs-width); - } - - .pagedjs_page:last-of-type { - margin-bottom: 10mm; - } - - .pagedjs_pagebox{ - box-shadow: 0 0 0 1px var(--color-pageBox); - } - - .pagedjs_left_page{ - z-index: 20; - width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width))!important; - } - - .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop { - border-color: transparent; - } - - .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-middle{ - width: 0; - } - - .pagedjs_right_page{ - z-index: 10; - position: relative; - left: calc(var(--pagedjs-bleed-left)*-1); - } - - /* show the margin-box */ - - .pagedjs_margin-top-left-corner-holder, - .pagedjs_margin-top, - .pagedjs_margin-top-left, - .pagedjs_margin-top-center, - .pagedjs_margin-top-right, - .pagedjs_margin-top-right-corner-holder, - .pagedjs_margin-bottom-left-corner-holder, - .pagedjs_margin-bottom, - .pagedjs_margin-bottom-left, - .pagedjs_margin-bottom-center, - .pagedjs_margin-bottom-right, - .pagedjs_margin-bottom-right-corner-holder, - .pagedjs_margin-right, - .pagedjs_margin-right-top, - .pagedjs_margin-right-middle, - .pagedjs_margin-right-bottom, - .pagedjs_margin-left, - .pagedjs_margin-left-top, - .pagedjs_margin-left-middle, - .pagedjs_margin-left-bottom { - box-shadow: 0 0 0 1px inset var(--color-marginBox); - } - - /* uncomment this part for recto/verso book : ------------------------------------ */ -/* - - .pagedjs_pages { - flex-direction: column; - width: 100%; - } - - .pagedjs_first_page { - margin-left: 0; - } - - .pagedjs_page { - margin: 0 auto; - margin-top: 10mm; - } - - .pagedjs_left_page{ - width: calc(var(--pagedjs-bleed-left) + var(--pagedjs-pagebox-width) + var(--pagedjs-bleed-left))!important; - } - - .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-crop{ - border-color: var(--pagedjs-crop-color); - } - - .pagedjs_left_page .pagedjs_bleed-right .pagedjs_marks-middle{ - width: var(--pagedjs-cross-size)!important; - } - - .pagedjs_right_page{ - left: 0; - } - */ - - - - /*--------------------------------------------------------------------------------------*/ - - - - /* uncomment this par to see the baseline : -------------------------------------------*/ - - /* - .pagedjs_pagebox { - --pagedjs-baseline: 22px; - --pagedjs-baseline-position: 5px; - --pagedjs-baseline-color: cyan; - background: linear-gradient(transparent 0%, transparent calc(var(--pagedjs-baseline) - 1px), var(--pagedjs-baseline-color) calc(var(--pagedjs-baseline) - 1px), var(--pagedjs-baseline-color) var(--pagedjs-baseline)), transparent; - background-size: 100% var(--pagedjs-baseline); - background-repeat: repeat-y; - background-position-y: var(--pagedjs-baseline-position); - } */ - - - /*--------------------------------------------------------------------------------------*/ -} - - - - - -/* Marks (to delete when merge in paged.js) */ - -.pagedjs_marks-crop{ - z-index: 999999999999; - -} - -.pagedjs_bleed-top .pagedjs_marks-crop, -.pagedjs_bleed-bottom .pagedjs_marks-crop{ - box-shadow: 1px 0px 0px 0px var(--pagedjs-crop-shadow); -} - -.pagedjs_bleed-top .pagedjs_marks-crop:last-child, -.pagedjs_bleed-bottom .pagedjs_marks-crop:last-child{ - box-shadow: -1px 0px 0px 0px var(--pagedjs-crop-shadow); -} - -.pagedjs_bleed-left .pagedjs_marks-crop, -.pagedjs_bleed-right .pagedjs_marks-crop{ - box-shadow: 0px 1px 0px 0px var(--pagedjs-crop-shadow); -} - -.pagedjs_bleed-left .pagedjs_marks-crop:last-child, -.pagedjs_bleed-right .pagedjs_marks-crop:last-child{ - box-shadow: 0px -1px 0px 0px var(--pagedjs-crop-shadow); -} diff --git a/static/main.css b/static/main.css index a4f8f46..e62d98f 100644 --- a/static/main.css +++ b/static/main.css @@ -1,16 +1,80 @@ body{ - background-color: #eaa0f9; - margin: 1vh 5vw 2vh 5vw; + min-width: 900px; } + +/* GENERAL RULES */ + +/* main title element that says "in octomode" */ +h1 em.octomode{ + color: darkorchid; +} + +/* navigation */ div#nav{ - position: absolute; - top:1em; - right: 1em; + position: fixed; + width: calc(100% - 1em); + top: 0; + left: 0; + margin: 0; + padding: 0 0.5em; } + div#nav h1{ + position: absolute; + width: auto; + line-height: 0; + margin: 0.75em 15px; + float: left; + } + div#nav div#buttons{ + margin: 0.5em 15px; + float: right; + } + div#nav input{ + min-width: 300px; + } +/* iframe rules */ iframe{ - width: 90vw; - height: 88vh; + width: 100%; + height: 100%; + border: none; +} +/* main content area */ +div#wrapper{ + position: fixed; + top: 50px; + left: 25px; + width: calc(100vw - 25px - 25px); + height: calc(100vh - 50px - 25px); } -input{ - min-width: 300px; + +/*div#logger-wrapper{ + position: fixed; + bottom: 0; + left: 0; + z-index: -1; + width: 100%; + height: 100%; + overflow-y: auto; + padding: 0 1em; + background-color: lightyellow; + display: flex; + flex-direction: column-reverse; + white-space: pre; +}*/ + +/* start page */ +body.start-page *{ + font-family: serif; + font-size: 115%; + font-weight: bold; } + +/* Z-INDEX */ + +div#wrapper, +div.pagedjs_pages{ + z-index: 1; +} +div#nav{ + z-index: 11; +} \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 4dd0aca..ecf92bc 100644 --- a/templates/base.html +++ b/templates/base.html @@ -2,20 +2,42 @@ - DSN documentation - + {{ name }} + + + + {% block head %} + {% endblock %} -

DSN documentation

-
{% block content %} {% endblock %} -
+ + +{% block footer %} +{% endblock %} diff --git a/templates/default-pandoc-template.html b/templates/default-pandoc-template.html new file mode 100644 index 0000000..28e52d8 --- /dev/null +++ b/templates/default-pandoc-template.html @@ -0,0 +1,32 @@ + + + + + + + + + + + $title$ + + + + +
+

$title$

+
+ +$if(toc)$ +
+$if(toc-title)$ +

$toc-title$

+$endif$ +$table-of-contents$ +
+$endif$ + +$body$ + + + diff --git a/templates/default.css b/templates/default.css new file mode 100644 index 0000000..325ee25 --- /dev/null +++ b/templates/default.css @@ -0,0 +1,10 @@ +@page{ + size: A5; +} +@page:first{ + background-color: pink; +} +section#cover, +section#TOC{ + page-break-after: always; +} \ No newline at end of file diff --git a/templates/default.md b/templates/default.md new file mode 100644 index 0000000..e2f1c2a --- /dev/null +++ b/templates/default.md @@ -0,0 +1,6 @@ +--- +title: hello! +language: en +--- + +# Hello? \ No newline at end of file diff --git a/templates/html.html b/templates/html.html index 3fba955..cc98110 100644 --- a/templates/html.html +++ b/templates/html.html @@ -1,5 +1,5 @@ {% extends "base.html" %} {% block content %} - +{{ html | safe }} {% endblock %} diff --git a/templates/stylesheet.html b/templates/index.html similarity index 51% rename from templates/stylesheet.html rename to templates/index.html index f8d1fe4..5b74f2d 100644 --- a/templates/stylesheet.html +++ b/templates/index.html @@ -1,6 +1,4 @@ {% extends "base.html" %} {% block content %} - {% endblock %} - diff --git a/templates/pad.html b/templates/pad.html index fad05ea..4d87c25 100644 --- a/templates/pad.html +++ b/templates/pad.html @@ -1,5 +1,5 @@ {% extends "base.html" %} {% block content %} - + {% endblock %} diff --git a/templates/pagedjs.html b/templates/pagedjs.html deleted file mode 100644 index 790afaf..0000000 --- a/templates/pagedjs.html +++ /dev/null @@ -1,5 +0,0 @@ -{% extends "base.html" %} - -{% block content %} - -{% endblock %} diff --git a/templates/pandoc-template-pagedjs.html b/templates/pandoc-template.html similarity index 71% rename from templates/pandoc-template-pagedjs.html rename to templates/pandoc-template.html index 22141b1..62757bb 100644 --- a/templates/pandoc-template-pagedjs.html +++ b/templates/pandoc-template.html @@ -4,17 +4,17 @@ - - + + $title$ -
-

$title$

+
+

$title$

$if(toc)$ diff --git a/templates/pdf.html b/templates/pdf.html new file mode 100644 index 0000000..eb78193 --- /dev/null +++ b/templates/pdf.html @@ -0,0 +1,30 @@ +{% extends "base.html" %} + +{% block content %} + +{% endblock %} + +{% block footer %} + +{% endblock %} diff --git a/templates/start.html b/templates/start.html new file mode 100644 index 0000000..09bf2ca --- /dev/null +++ b/templates/start.html @@ -0,0 +1,13 @@ + + + + + octomode + + + +
+

in octomode

+
+ +