import urllib.request
import os
import re
import json
import jinja2
# Notes are here: https://pad.vvvvvvaria.org/volumetric-regimes-in-process.
STATIC_FOLDER_PATH = '.' # without trailing slash
PUBLIC_STATIC_FOLDER_PATH = '.' # without trailing slash
TEMPLATES_DIR = './templates'
# This uses a low quality copy of all the images
# (using a folder with the name "images-small",
# which stores a copy of all the images generated with:
# $ mogrify -quality 5% -adaptive-resize 25% -remap pattern:gray50 * )
fast = False
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, wiki):
"""
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')
# tmp list for filename replacements
replaced = []
images.sort()
images.reverse() # reverse to make sure that 01.png does not override Image01.png in the filename replacements later
# 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
# !!!!!
# turned off for preparing final files (AUG 2022)
# !!!!!
# 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 image link (from wiki folder structure to local folder)
image_path = f'{ PUBLIC_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
img_path_patterns = [rf'(? { image_path }') # for debugging: each image should have the correct match!
html = html.replace(match, image_path)
replaced.append(match)
return html
def add_item_inventory_links(html):
"""
html = string (HTML)
"""
# THROUGHOUT THE BOOK
# Find all references in the text to the item index
matches = re.findall(r'\w.*?Item \d\d\d.*?\w\w\w', html) # Dodgy attempt to find unique patterns for each mentioning of Item ###
index = {}
for match in matches:
item_match = re.search(r'Item \d\d\d', match).group()
number = item_match.replace('Item ', '').strip()
text_before = re.search(rf'\w.*?Item { number }', match).group().replace(f'Item { number }', '')
text_after = re.search(rf'Item { number }.*?\w\w\w', match).group().replace(f'Item { number }', '')
if not number in index:
index[number] = []
count = 1
else:
count = index[number][-1] + 1
index[number].append(count)
item_id = f'ii-{ number }-{ index[number][-1] }'
# print(f'match: { number } --> { item_id } --> { match }')
html = html.replace(match, f'{ text_before }Item { number }{ text_after }')
# IN THE ITEM INDEX
# Also add a around the index nr to style it
matches = re.findall(r'''', '''
References
''', html) # add id="references" to h3 and ul, so the elements can be selected with CSS
html = html.replace('src="./images/Userinfo.jpg"', 'src="./images/Userinfo.svg"') # This image is not on the wiki
html = html.replace('srcset="./images/Userinfo.jpg 1.5x, ./images/Userinfo.jpg 2x"', 'srcset="./images/Userinfo.svg 1.5x, ./images/Userinfo.svg 2x"') # This image is not on the wiki
html = html.replace('src="./images/Continuum_brighton.png"', 'src="./images/Continuum_brighton.svg"') # This image is not on the wiki
html = html.replace('srcset="./images/Continuum_brighton.png 1.5x, ./images/Continuum_brighton.png 2x"', 'srcset="./images/Continuum_brighton.svg 1.5x, ./images/Continuum_brighton.svg 2x"') # This image is not on the wiki
# html = html.replace('src="./images/Topology-typography-1A.png"', 'src="./images/Topology-typography-1A.svg"') # This image is not on the wiki
# html = html.replace('src="./images/Topology-typography-1B.png"', 'src="./images/Topology-typography-1B.svg"') # This image is not on the wiki
# html = html.replace('src="./images/Topology-typography-2A.png"', 'src="./images/Topology-typography-2A.svg"') # This image is not on the wiki
# html = html.replace('src="./images/Topology-typography-2B.png"', 'src="./images/Topology-typography-2B.svg"') # This image is not on the wiki
# html = html.replace('srcset="./images/Topology-typography-1A.png"', 'srcset="./images/Topology-typography-1A.svg"') # This image is not on the wiki
# html = html.replace('srcset="./images/Topology-typography-1B.png"', 'srcset="./images/Topology-typography-1B.svg"') # This image is not on the wiki
# html = html.replace('srcset="./images/Topology-typography-2A.png"', 'srcset="./images/Topology-typography-2A.svg"') # This image is not on the wiki
# html = html.replace('srcset="./images/Topology-typography-2B.png"', 'srcset="./images/Topology-typography-2B.svg"') # This image is not on the wiki
html = html.replace('trans*feminis', 'trans✶feminis') # changing stars
html = html.replace('Trans*feminis', 'Trans✶feminis') # changing stars
html = html.replace('star (*)', 'star (✶)') # changing stars
html = html.replace('Our trans*feminist lens is sharpened by queer and anti-colonial sensibilities, and oriented towards (but not limited to) trans*generational, trans*media, trans*disciplinary, trans*geopolitical, trans*expertise, and trans*genealogical forms of study.', 'Our trans✶feminist lens is sharpened by queer and anti-colonial sensibilities, and oriented towards (but not limited to) trans✶generational, trans✶media, trans✶disciplinary, trans✶geopolitical, trans✶expertise, and trans✶genealogical forms of study.') # changing stars
html = html.replace('
Invasive imagination and its agential cuts
', 'Invasive imagination
')
html = html.replace('
and its agential cutsVolumetric Regimes: Material cultures of quantified presence
', 'Volumetric Regimes:
')
html = html.replace('
Material cultures of
quantified presenceSomatopologies (materials for a movie in the making)
', 'Somatopologies (materials
')
html = html.replace('
for a movie in the making)Signs of clandestine disorder: The continuous aftermath of 3D-computationalism
', 'Signs of clandestine disorder:
')
html = html.replace('
The continuous
aftermath of 3D-
computationalismThe Industrial Continuum of 3D
', 'The Industrial Continuum
')
html = html.replace('
of 3DDepths and Densities: Accidented and dissonant spacetimes
', 'Depths and Densities:
')
html = html.replace('
Accidented
and dissonant
spacetimesOpen Boundary Conditions: a grid for intensive study
', 'Open Boundary Conditions:
')
html = html.replace('T*fRP', 'T✶fRP')
html = html.replace('trans*', 'trans✶')
html = html.replace('Trans*', 'trans✶')
html = html.replace('(*)', '(✶)')
html = html.replace('✶', '✶')
html = html.replace('
a grid for intensive study
we do!”') # force line break
html = html.replace('I find gestationality useful and very exciting.', 'I find gestationality useful and very
exciting.') # force line break
html = html.replace('world.html https://docs.blender.org/manual/en/dev/rende', 'world.html
https://docs.blender.org/manual/en/dev/rende') # force line break
html = html.replace('Nerea Calvillo, Eric Snodgrass', 'Nerea Calvillo, Eric
Snodgrass') # force line break
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
# Missing sentences hack zone........
html = html.replace('from on-line hosting, designing, peer-reviewing', 'from on-line hosting, designing,
peer-reviewing') html = html.replace('''revolving of all matters.
''', '''revolving of all matters..*?
''' # title + author pattern2 = r'''.*?
''' # exceptions: custom running headers pattern3 = r'''Jara Rocha, Femke Snelting
''' pattern5 = r'''Possible Bodies \(Jara Rocha, Femke Snelting\)
''' pattern6 = r'''Maria Dada
''' pattern7 = r'''Phil Langley in conversation with Possible Bodies
''' results = re.findall(rf'{pattern1}|{pattern2}|{pattern3}|{pattern4}|{pattern5}|{pattern6}|{pattern7}', html) for match in results: html = html.replace(match, f'3D computation has historically co-evolved with Modern technosciences, and aligned with the regimes of optimization, normalization and hegemonic world order. The legacies and projections of industrial development leave traces of that imaginary and tell the stories of a lively tension between “the probable” and “the possible”. Defined as the techniques for measuring volumes, volumetrics all too easily (re)produce and accentuate the probable, and this process is intensified within the technocratic realm of contemporary hyper-computation.
This book brings together diverse materials from an ongoing trans✶feminist conversation between artists, software developers and theorists working with techniques and technologies for detecting, tracking, capturing, printing, modeling and rendering volumes.''', '''
3D computation has historically co-evolved with Modern technosciences, and aligned with the regimes of optimiza-
tion, normalization and hegemonic world order. The lega-
cies and projections of industrial development leave traces of that imaginary and tell the stories of a lively tension
between “the probable” and “the possible”. Defined as the techniques for measuring volumes, volumetrics all too easily (re)produce and accentuate the probable, and this process is intensified within the technocratic realm of
contemporary hyper-computation.
This book brings together diverse materials from an ongoing trans✶feminist conversation between artists, software developers and theorists working with
techniques and technologies for detecting, tracking, capturing, printing, modeling and rendering volumes.''') # Aug 2022
return html
def clean_up(html):
"""
html = string (HTML)
"""
html = re.sub(r'\[.*edit.*\]', '', html) # remove the [edit]
html = re.sub(r'href="/index.php\?title=', 'href="#', html) # remove the internal wiki links
html = re.sub(r'[(?=\d)', '', html) # remove left footnote bracket [
html = re.sub(r'(?<=\d)]', '', html) # remove right footnote bracket ]
return html
def fast_loader(html):
"""
html = string (HTML)
"""
if fast == True:
html = html.replace('/images/', '/images-small/')
print('--- rendered in FAST mode ---')
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, wiki)
html = clean_up(html)
html = add_item_inventory_links(html)
html = tweaking(html)
html = fast_loader(html)
else:
html = None
return html
def save(html, pagename):
"""
html = string (HTML)
pagename = string
"""
if __name__ == "__main__":
# command-line
# save final page that will be used with PagedJS
template_file = open(f'{ STATIC_FOLDER_PATH }/{ TEMPLATES_DIR }/template.html').read()
template = jinja2.Template(template_file)
doc = template.render(publication_unfolded=html, title=pagename)
html_file = f'{ STATIC_FOLDER_PATH }/{ pagename }.html'
print('Saving HTML:', html_file)
with open(html_file, 'w') as out:
out.write(doc)
out.close()
# save extra html page for debugging (CLI only)
template_file = open(f'{ STATIC_FOLDER_PATH }/{ TEMPLATES_DIR }/template.inspect.html').read()
template = jinja2.Template(template_file)
doc = template.render(publication_unfolded=html, 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(doc)
out.close()
else:
# Flask application
with open(f'{ STATIC_FOLDER_PATH }/Unfolded.html', 'w') as out:
out.write(html) # save the html to a file (without