Turning folders into web pages with Python: Difference between revisions
No edit summary |
|||
| Line 22: | Line 22: | ||
Just copy and paste! | Just copy and paste! | ||
/var/www/html/SI29/file-sharing/gallery/assets/ | |||
===5. Work on main.py=== | ===5. Work on main.py=== | ||
Revision as of 16:25, 10 February 2026
For the prototyping class on 10 February 2026 in the context of SI29.
Gallery example
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!
/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
$ 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.