Turning folders into web pages with Python: Difference between revisions
m (Manetta moved page Gallery prototype to Turning folders into web pages with Python) |
|||
| (10 intermediate revisions by 2 users not shown) | |||
| Line 15: | Line 15: | ||
A '''static site generator''' ('''SSG''') is a tools/script that helps you to make a website that is based on a bunch of static web pages, that don't use php, flask, node or other web application frameworks. Instead, a SSG is often loved for the fact that it creates a folder of static HTML/CSS/JS files that can be uploaded to a simple web host and require less maintenance, as they don't require a specific more complex technical setup. | A '''static site generator''' ('''SSG''') is a tools/script that helps you to make a website that is based on a bunch of static web pages, that don't use php, flask, node or other web application frameworks. Instead, a SSG is often loved for the fact that it creates a folder of static HTML/CSS/JS files that can be uploaded to a simple web host and require less maintenance, as they don't require a specific more complex technical setup. | ||
Examples of | '''Well-known SSG projects''' include: | ||
* [https://getpelican.com/ Pelican] | |||
* [https://gohugo.io/ Hugo] | |||
* [https://www.11ty.dev/ Eleventy] | |||
'''Examples''' of artistic projects/scripts/practices that generate static web pages: | |||
* [https://git.vvvvvvaria.org/varia/bots/src/branch/master/LogBot varia's logbot] + [https://vvvvvvaria.org/logs/ generated logs] | * [https://git.vvvvvvaria.org/varia/bots/src/branch/master/LogBot varia's logbot] + [https://vvvvvvaria.org/logs/ generated logs] | ||
* [https://draw-it-with-others.org/small-loops/ small-loops], by DIWO | * [https://draw-it-with-others.org/small-loops/ small-loops], by DIWO [credentials: <span style="background: dodgerblue; color: dodgerblue">tofu : esseresalaminioggi</span> | ||
* [https://git.vvvvvvaria.org/varia/distribusi distribusi], examples where you can see it in use: | * [https://git.vvvvvvaria.org/varia/distribusi distribusi], examples where you can see it in use: | ||
** https://archive.simonbrowne.page/ | ** https://archive.simonbrowne.page/ | ||
| Line 24: | Line 30: | ||
** https://vvvvvvaria.org/archive/ | ** https://vvvvvvaria.org/archive/ | ||
** https://networksofonesown.vvvvvvaria.org/ | ** https://networksofonesown.vvvvvvaria.org/ | ||
* [https://simonrepp.com/faircamp/ Faircamp], a SSG for audio producers, by Simon Repp | |||
==How to make this?== | ==How to make this?== | ||
| Line 46: | Line 53: | ||
Just copy and paste! | Just copy and paste! | ||
or use scp: | |||
/var/www/html/SI29/file-sharing/gallery/assets/ | $ scp myimagefolder/* /var/www/html/SI29/file-sharing/gallery/assets/ | ||
===5. Work on main.py=== | ===5. Work on main.py=== | ||
| Line 89: | Line 98: | ||
===7. Run the script=== | ===7. Run the script=== | ||
First install jinja2 if you don't have it installed: | |||
$ uv pip install jinja2 | |||
Then run the Python script: | |||
$ uv run main.py | $ uv run main.py | ||
| Line 239: | Line 254: | ||
Hopefully this triggers ideas for more extension points. | Hopefully this triggers ideas for more extension points. | ||
[[Category:Workbooks]] | |||
Latest revision as of 16:47, 21 April 2026
For the prototyping class on 10 February 2026 in the context of SI29.
Turning a folder of pictures into a photo gallery
generating HTML + CSS with Python + Jinja
This is a prototype to generate web pages based on a collection of files stored on your computer or a shared server.
The following code will generate this photo gallery: https://hub.xpub.nl/sergio/SI29/file-sharing/gallery/
Context
This prototype is basically showing you how you can make your own custom static site generator.
A static site generator (SSG) is a tools/script that helps you to make a website that is based on a bunch of static web pages, that don't use php, flask, node or other web application frameworks. Instead, a SSG is often loved for the fact that it creates a folder of static HTML/CSS/JS files that can be uploaded to a simple web host and require less maintenance, as they don't require a specific more complex technical setup.
Well-known SSG projects include:
Examples of artistic projects/scripts/practices that generate static web pages:
- varia's logbot + generated logs
- small-loops, by DIWO [credentials: tofu : esseresalaminioggi
- distribusi, examples where you can see it in use:
- Faircamp, a SSG for audio producers, by Simon Repp
How to make this?
1. Install uv
(if you don't have uv already)
https://docs.astral.sh/uv/getting-started/installation/
$ curl -LsSf https://astral.sh/uv/install.sh | sh
2. Initialize project
$ uv init gallery
3. Prepare an assets folder
$ mkdir assets
4. Put some files in the assets folder
Just copy and paste!
or use scp:
$ scp myimagefolder/* /var/www/html/SI29/file-sharing/gallery/assets/
5. Work on main.py
from glob import glob
from jinja2 import Template
def main():
assets = glob('assets/*')
with open('template.html','r') as f:
html_template = f.read()
jinja_template = Template(html_template)
output = jinja_template.render(assets=assets)
with open('index.html', 'w') as f:
f.write(output)
if __name__ == "__main__":
main()
6. Work on your template.html
<style>
img {
max-width: 200px;
object-fit: contain;
}
</style>
<ol>
{% for asset in assets %}
<li><img src="{{asset}}"/></li>
{% endfor %}
</ol>
7. Run the script
First install jinja2 if you don't have it installed:
$ uv pip install jinja2
Then run the Python script:
$ uv run main.py
8. See the result
Open the index.html file in your browser.
Possible extension points
Timestamps
# Sort by timestamp
assets = sorted(assets, key=os.path.getmtime)
# You can reverse the sort by passing reverse=True to the sorted function
assets = sorted(assets, key=os.path.getmtime, reverse=True)
Media type
File size
# Sort by size
assets = sorted(assets, key=os.path.getsize)
Anecdotes
How about setting up a small gossip system for our gallery?
Choose a file to annotate, and create a file with the extension .anecdote
$ touch photo_1_2026-02-02_11-56-09.jpg.anecdote
Open the anecdote with a text editor and write your gossips there!
$ nano photo_1_2026-02-02_11-56-09.jpg.anecdote
Then in our python code we check for anecdotes:
[...]
assets_or_anecdotes = []
for asset in assets:
# Every asset has a file...
file_maybe_anecdote = {
"file": asset
}
# But some also have an anecdote
if asset.endswith('.anecdote'):
# If it is we read its content into the file_maybe_anecdote dictionary
with open(asset, 'r') as a:
file_maybe_anecdote['anecdote'] = a.read()
# Append it to the list of assets
assets_or_anecdotes.append(file_maybe_anecdote)
[...]
output = jinja_template.render(assets=assets_or_anecdotes)
In the template, we use conditionals to check if an asset is an anecdote or not, and we render it accordingly.
<ol>
{% for asset in assets %}
{% if asset.anecdote %}
<p>{{ asset.anecdote }}</p>
{% else %}
<li><img src="{{asset.file}}"/></li>
{% endif %}
{% endfor %}
</ol>
(to try out: how to make more anecdotes for the same file?)
Alt text
How to repurpose the anecdotes system to write alt captions for the images?
Hyperlinks
Structured Metadata
# Add some metadata to the assets list
import os
import pwd
from datetime import datetime
#[...]
assets_with_meta = []
for asset in assets:
# Load and parse stats about a file
# https://docs.python.org/3/library/stat.html
stat = os.stat(asset)
size = stat.st_size
# Work with datetime
# https://www.programiz.com/python-programming/datetime/strftime
last_modified = datetime
.fromtimestamp(stat.st_mtime)
.strftime("%m/%d/%Y, %H:%M:%S")
# Get username from user id
# https://stackoverflow.com/questions/842059#comment3162593_2899055
user = pwd.getpwuid(stat.st_uid).pw_name
# Create a dictionary with all the info
asset_with_meta = {
"file": asset,
"user": user,
"last_modified": last_modified,
"size": size
}
# Append it to the list of assets
assets_with_meta.append(asset_with_meta)
Then you can pass your assets_with_meta list to the template...
output = jinja_template.render(assets=assets_with_meta)
And play around with it in the template.html file
<ol>
{% for asset in assets %}
<li>
<img src="{{asset.file}}"/>
{{asset.user}} - {{asset.last_modified}} - {{asset.size}}
</li>
{% endfor %}
</ol>
etc!!!
Hopefully this triggers ideas for more extension points.