manetta
3 years ago
23 changed files with 62758 additions and 0 deletions
@ -0,0 +1,13 @@ |
|||
all: run |
|||
|
|||
run: |
|||
python3 -m http.server |
|||
|
|||
update: |
|||
python3 update.py |
|||
|
|||
upload: |
|||
scp -r ./static/Unfolded.html ./static/css/ ./static/js/ ./static/fonts/ varia:public_html/volumetric-regimes/ |
|||
|
|||
uploadimages: |
|||
scp -r ./static/images/ varia:public_html/volumetric-regimes/ |
@ -0,0 +1,3 @@ |
|||
flask |
|||
etherpump |
|||
weasyprint |
@ -0,0 +1,180 @@ |
|||
/* 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); |
|||
} |
@ -0,0 +1,52 @@ |
|||
body{ |
|||
background-color: #a6e89d; |
|||
margin: 1vh 5vw 2vh 5vw; |
|||
z-index: 1; |
|||
} |
|||
div#nav{ |
|||
position: fixed; |
|||
width: calc(100% - 2em); |
|||
margin: 1em; |
|||
text-align: right; |
|||
left: 0; |
|||
top: 0; |
|||
z-index: 999; |
|||
} |
|||
div#nav a#home, |
|||
div#nav span#loading, |
|||
div#nav a#update{ |
|||
float: left; |
|||
padding-right: 0.25em; |
|||
} |
|||
div#nav span#loading{ |
|||
display: none; |
|||
margin: 0.35em 0.25em; |
|||
color: fuchsia; |
|||
opacity: 0; |
|||
animation: fade 2s linear; |
|||
} |
|||
@keyframes fade { |
|||
0%,100% { opacity: 0 } |
|||
50% { opacity: 1 } |
|||
} |
|||
iframe{ |
|||
width: 90vw; |
|||
height: 88vh; |
|||
} |
|||
input{ |
|||
min-width: 300px; |
|||
} |
|||
div#index ul{ |
|||
padding: 0; |
|||
margin: 0 0 0 5em; |
|||
width: 750px; |
|||
} |
|||
div#index ul li{ |
|||
margin-bottom: 1em; |
|||
list-style: none; |
|||
} |
|||
div#index ul li::before{ |
|||
content: "▁ ▂ ▃ ▄ ▅ ▆ ▇ █"; |
|||
float: left; |
|||
margin-left: -9.5em; |
|||
} |
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,34 @@ |
|||
<!DOCTYPE html> |
|||
<html lang='en'> |
|||
<head> |
|||
<meta charset="utf-8" /> |
|||
<title>{{ title }}</title> |
|||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/main.css')}}"> |
|||
{% block head %} |
|||
{% endblock %} |
|||
</head> |
|||
<body> |
|||
{% block nav %} |
|||
{% endblock %} |
|||
<div id="wrapper"> |
|||
{% block content %} |
|||
{% endblock %} |
|||
</div> |
|||
</body> |
|||
<script> |
|||
window.addEventListener('load', function () { |
|||
|
|||
// Insert the nav buttons, after the page is loaded |
|||
const nav = document.createElement('div'); |
|||
nav.id = 'nav'; |
|||
nav.innerHTML = '<a id="home" href="/"><button>/</button></a> <a id="update" href="/update/" onclick="load()"><button>update</button></a><span id="loading">loading</span><a id="pdf" href="/pagedjs/"><button>pdf</button></a> <a id="inspect" href="/inspect/"><button>inspect</button></a> <a id="stylesheet" href="/stylesheet/"><button>stylesheet</button></a>: <input type="text" name="pad" value="https://pad.vvvvvvaria.org/volumetric-regimes.css">'; |
|||
document.body.insertBefore(nav, document.body.firstChild) |
|||
}) |
|||
function load(){ |
|||
const loading = document.getElementById("loading"); |
|||
loading.style.display = 'inline-block'; |
|||
} |
|||
</script> |
|||
{% block footer %} |
|||
{% endblock %} |
|||
</html> |
@ -0,0 +1,19 @@ |
|||
{% extends "flask/base.html" %} |
|||
|
|||
{% block content %} |
|||
<div id="index"> |
|||
<br> |
|||
<br> |
|||
<h1>Volumetric Regimes</h1> |
|||
<h1>Shared Book/PDF rendering environment</h1> |
|||
<br> |
|||
<br> |
|||
<ul> |
|||
<li><strong>update</strong>: Update the materials from the <a href="https://possiblebodies.constantvzw.org/book/index.php?title=Unfolded" target="new">Unfolded wiki page</a> (saved as <a href="{{ url_for('static', filename='Unfolded.html')}}">Unfolded.html</a>)</li> |
|||
<li><strong>pdf</strong>: Preview the Book/PDF file, which is displayed in the browser using Paged.js</li> |
|||
<li><strong>inspect</strong>: Dive into the <a href="{{ url_for('static', filename='Unfolded.html')}}">Unfolded.html</a> webpage that renders the Book/PDF</li> |
|||
<li><strong>stylesheet</strong>: Change the layout of the Book/PDF (saved as <a href="{{ url_for('static', filename='css/volumetric-regimes.css')}}">volumetric-regimes.css</a>)</li> |
|||
</ul> |
|||
</div> |
|||
{% endblock %} |
|||
|
@ -0,0 +1,9 @@ |
|||
{% extends "flask/base.html" %} |
|||
|
|||
{% block head %} |
|||
<link href="{{ url_for('static', filename='css/volumetric-regimes.css')}}" rel="stylesheet" type="text/css" media="screen"> |
|||
{% endblock %} |
|||
|
|||
{% block content %} |
|||
{{ publication_unfolded | safe }} |
|||
{% endblock %} |
@ -0,0 +1,27 @@ |
|||
{% extends "flask/base.html" %} |
|||
|
|||
{% block head %} |
|||
<script src="{{ url_for('static', filename='js/paged.js')}}" type="text/javascript"></script> |
|||
<script src="{{ url_for('static', filename='js/paged.polyfill.js')}}" type="text/javascript"></script> |
|||
<link href="{{ url_for('static', filename='css/interface.css')}}" rel="stylesheet" type="text/css"> |
|||
<link href="{{ url_for('static', filename='css/volumetric-regimes.css')}}" rel="stylesheet" type="text/css" media="print"> |
|||
{% endblock %} |
|||
|
|||
{% block content %} |
|||
{{ publication_unfolded | safe }} |
|||
{% endblock %} |
|||
|
|||
{% block footer %} |
|||
<script> |
|||
window.addEventListener('load', function () { |
|||
|
|||
// Add the main.css again, to load the stylesheet for the nav |
|||
var cssLink = document.createElement('link'); |
|||
cssLink.rel = 'stylesheet'; |
|||
cssLink.href = '/static/css/main.css'; |
|||
var head = document.getElementsByTagName('head')[0]; |
|||
head.insertBefore(cssLink, head.firstChild); |
|||
|
|||
}) |
|||
</script> |
|||
{% endblock %} |
@ -0,0 +1,6 @@ |
|||
{% extends "flask/base.html" %} |
|||
|
|||
{% block content %} |
|||
<iframe src="https://pad.vvvvvvaria.org/volumetric-regimes.css"></iframe> |
|||
{% endblock %} |
|||
|
@ -0,0 +1,15 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<script src="./static/js/paged.js" type="text/javascript"></script> |
|||
<script src="./static/js/paged.polyfill.js" type="text/javascript"></script> |
|||
<link href="./static/css/interface.css" rel="stylesheet" type="text/css"> |
|||
<link href="./static/css/print.css" rel="stylesheet" type="text/css" media="print"> |
|||
</head> |
|||
<body> |
|||
<div id="wrapper"> |
|||
{{ publication_unfolded }} |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,12 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<link href="./static/css/print.css" rel="stylesheet" type="text/css" media="print"> |
|||
</head> |
|||
<body> |
|||
<div id="wrapper"> |
|||
{{ publication_unfolded }} |
|||
</div> |
|||
</body> |
|||
</html> |
@ -0,0 +1,155 @@ |
|||
import urllib.request |
|||
import os |
|||
import re |
|||
import json |
|||
import jinja2 |
|||
|
|||
STATIC_FOLDER_PATH = './static' # without trailing slash |
|||
|
|||
def API_request(url, pagename): |
|||
""" |
|||
url = API request url (string) |
|||
data = { 'query': |
|||
'pages' : |
|||
pageid : { |
|||
'links' : { |
|||
'?' : '?' |
|||
'title' : 'pagename' |
|||
} |
|||
} |
|||
} |
|||
} |
|||
""" |
|||
response = urllib.request.urlopen(url).read() |
|||
data = json.loads(response) |
|||
|
|||
# Save response as JSON to be able to inspect API call |
|||
json_file = f'{ STATIC_FOLDER_PATH }/{ pagename }.json' |
|||
print('Saving JSON:', json_file) |
|||
with open(json_file, 'w') as out: |
|||
out.write(json.dumps(data, indent=4)) |
|||
out.close() |
|||
|
|||
return data |
|||
|
|||
def download_media(html, images): |
|||
""" |
|||
html = string (HTML) |
|||
images = list of filenames (str) |
|||
""" |
|||
# check if 'images/' already exists |
|||
if not os.path.exists(f'{ STATIC_FOLDER_PATH }/images'): |
|||
os.makedirs(f'{ STATIC_FOLDER_PATH }/images') |
|||
|
|||
# download media files |
|||
for filename in images: |
|||
filename = filename.replace(' ', '_') # safe filenames |
|||
|
|||
# check if the image is already downloaded |
|||
# if not, then download the file |
|||
if not os.path.isfile(f'{ STATIC_FOLDER_PATH }/images/{ filename }'): |
|||
|
|||
# first we search for the full filename of the image |
|||
url = f'{ wiki }/api.php?action=query&list=allimages&aifrom={ filename }&format=json' |
|||
response = urllib.request.urlopen(url).read() |
|||
data = json.loads(response) |
|||
|
|||
# we select the first search result |
|||
# (assuming that this is the image we are looking for) |
|||
image = data['query']['allimages'][0] |
|||
|
|||
# then we download the image |
|||
image_url = image['url'] |
|||
image_filename = image['name'] |
|||
print('Downloading:', image_filename) |
|||
image_response = urllib.request.urlopen(image_url).read() |
|||
|
|||
# and we save it as a file |
|||
image_path = f'{ STATIC_FOLDER_PATH }/images/{ image_filename }' |
|||
out = open(image_path, 'wb') |
|||
out.write(image_response) |
|||
out.close() |
|||
|
|||
import time |
|||
time.sleep(3) # do not overload the server |
|||
|
|||
# replace src link |
|||
image_path = f'/{ STATIC_FOLDER_PATH }/images/{ filename }' # here the images need to link to the / of the domain, for flask :/// confusing! this breaks the whole idea to still be able to make a local copy of the file |
|||
html = re.sub(rf'src="/book/images/.*{ filename }"', f'src="{ image_path }"', html) |
|||
|
|||
return html |
|||
|
|||
def clean_up(html): |
|||
""" |
|||
html = string (HTML) |
|||
""" |
|||
html = re.sub(r'\[.*edit.*\]', '', html) # remove the [edit] |
|||
html = re.sub(r'href="/book/index.php\?title=', 'href="#', html) # remove the internal wiki links |
|||
return html |
|||
|
|||
def parse_page(pagename, wiki): |
|||
""" |
|||
pagename = string |
|||
html = string (HTML) |
|||
""" |
|||
parse = f'{ wiki }/api.php?action=parse&page={ pagename }&pst=True&format=json' |
|||
data = API_request(parse, pagename) |
|||
# print(json.dumps(data, indent=4)) |
|||
if 'parse' in data: |
|||
html = data['parse']['text']['*'] |
|||
images = data['parse']['images'] |
|||
html = download_media(html, images) |
|||
html = clean_up(html) |
|||
else: |
|||
html = None |
|||
|
|||
return html |
|||
|
|||
def save(html, pagename, publication_unfolded): |
|||
""" |
|||
html = string (HTML) |
|||
pagename = string |
|||
""" |
|||
if html: |
|||
|
|||
# save final page that will be used with PagedJS |
|||
template_file = open(f'{ STATIC_FOLDER_PATH }/local/template.html').read() |
|||
template = jinja2.Template(template_file) |
|||
html = template.render(publication_unfolded=publication_unfolded, title=pagename) |
|||
|
|||
html_file = f'{ STATIC_FOLDER_PATH }/{ pagename }.html' |
|||
print('Saving HTML:', html_file) |
|||
with open(html_file, 'w') as out: |
|||
out.write(html) |
|||
out.close() |
|||
|
|||
# save extra html page for debugging |
|||
template_file = open(f'{ STATIC_FOLDER_PATH }/local/template.inspect.html').read() |
|||
template = jinja2.Template(template_file) |
|||
html = template.render(publication_unfolded=publication_unfolded, title=pagename) |
|||
|
|||
html_file = f'{ STATIC_FOLDER_PATH }/{ pagename }.inspect.html' |
|||
print('Saving HTML:', html_file) |
|||
with open(html_file, 'w') as out: |
|||
out.write(html) |
|||
out.close() |
|||
|
|||
def update_material_now(pagename, wiki): |
|||
""" |
|||
pagename = string |
|||
publication_unfolded = string (HTML) |
|||
""" |
|||
publication_unfolded = parse_page(pagename, wiki) |
|||
|
|||
return publication_unfolded |
|||
|
|||
# --- |
|||
|
|||
if __name__ == "__main__": |
|||
|
|||
wiki = 'https://possiblebodies.constantvzw.org/book' # remove tail slash '/' |
|||
pagename = 'Unfolded' |
|||
|
|||
publication_unfolded = update_material_now(pagename, wiki) # download the latest version of the page |
|||
save(publication_unfolded, pagename, publication_unfolded) # save the page to file |
|||
|
@ -0,0 +1,65 @@ |
|||
import flask |
|||
import urllib, json |
|||
import os |
|||
from update import * |
|||
|
|||
# Create the application. |
|||
APP = flask.Flask(__name__) |
|||
|
|||
# --- |
|||
|
|||
PROJECT_NAME = 'volumetric-regimes' |
|||
DIR_PATH = '.' # without trailing slash |
|||
PORTNUMBER = 5522 |
|||
WIKI = 'https://possiblebodies.constantvzw.org/book' # remove tail slash '/' |
|||
PAGENAME = 'Unfolded' |
|||
STYLESHEET = f'{ PROJECT_NAME }.css' |
|||
|
|||
# --- |
|||
|
|||
|
|||
def download(STYLESHEET): |
|||
# using etherpump |
|||
os.system(f'{ DIR_PATH }/venv/bin/etherpump gettext { STYLESHEET } > { DIR_PATH }/static/css/{ STYLESHEET }') |
|||
|
|||
@APP.route('/', methods=['GET']) |
|||
def pad(): |
|||
if not os.path.exists(f'{ DIR_PATH }/static/Unfolded.html'): |
|||
download(STYLESHEET) # download the stylesheet pad |
|||
publication_unfolded = update_material_now(PAGENAME, WIKI) # download the latest version of the page |
|||
with open(f'{ DIR_PATH }/static/Unfolded.html', 'w') as out: |
|||
out.write(publication_unfolded) # save the html (without <head>) to file |
|||
else: |
|||
publication_unfolded = open(f'{ DIR_PATH }/static/Unfolded.html', 'r').read() |
|||
|
|||
return flask.render_template('flask/index.html', title=PROJECT_NAME) |
|||
|
|||
@APP.route('/update/', methods=['GET', 'POST']) |
|||
def update(): |
|||
publication_unfolded = update_material_now(PAGENAME, WIKI) # download the latest version of the page |
|||
with open(f'{ DIR_PATH }/static/Unfolded.html', 'w') as out: |
|||
out.write(publication_unfolded) # save the html (without <head>) to file |
|||
|
|||
return flask.render_template('flask/index.html', title=PROJECT_NAME) |
|||
|
|||
@APP.route('/pagedjs/', methods=['GET', 'POST']) |
|||
def pagedjs(): |
|||
download(STYLESHEET) # download the stylesheet pad |
|||
publication_unfolded = open(f'{ DIR_PATH }/static/Unfolded.html', 'r').read() |
|||
|
|||
return flask.render_template('flask/pagedjs.html', publication_unfolded=publication_unfolded, STYLESHEET=STYLESHEET) |
|||
|
|||
@APP.route('/inspect/', methods=['GET', 'POST']) |
|||
def inspect(): |
|||
download(STYLESHEET) # download the stylesheet pad |
|||
publication_unfolded = open(f'{ DIR_PATH }/static/Unfolded.html', 'r').read() |
|||
|
|||
return flask.render_template('flask/inspect.html', publication_unfolded=publication_unfolded, STYLESHEET=STYLESHEET) |
|||
|
|||
@APP.route('/stylesheet/', methods=['GET']) |
|||
def stylesheet(): |
|||
return flask.render_template('flask/stylesheet.html') |
|||
|
|||
if __name__ == '__main__': |
|||
APP.debug=True |
|||
APP.run(port=f'{ PORTNUMBER }') |
Loading…
Reference in new issue