Compare commits

...

10 Commits

Author SHA1 Message Date
gauthiier bf4c1e0cab css media 2024-08-23 10:16:24 +02:00
gauthiier e3801fdb8c header 2023-09-12 08:38:24 +02:00
gauthiier 265cbb4e70 txt-md 2023-09-12 08:36:35 +02:00
gauthiier 9d84b99449 allo (bis) 2023-08-03 11:31:30 +02:00
gauthiier 01d08880dc allo (bis) 2023-08-03 11:27:57 +02:00
gauthiier 07e2e50124 allo 2023-08-03 11:24:25 +02:00
gauthiier 7ec2394871 cleanup 2023-08-03 11:23:55 +02:00
gauthiier 038b5a6bf1 imgconv for lod 2023-08-03 11:14:49 +02:00
gauthiier 3e6c8aa179 auto script 2023-07-19 12:09:39 +02:00
gauthiier 509139d57b venv reqs 2023-07-19 12:06:50 +02:00
10 changed files with 321 additions and 141 deletions
+1 -8
View File
@@ -1,11 +1,4 @@
.static/settings.json
venv/
+++/*.jpg
+++/*.jpeg
+++/*.pdf
+++/Screen-Shot-2014-05-26-at-20.40.24-b.png
+++/bb15.png
+++/533201N0032129W_from_the_Sea_poster.png
+++/key.asc
+++/index.html
.DS_Store
__pycache__
+6 -1
View File
@@ -1,2 +1,7 @@
__sssstatic __sssstatic __sssstatic __sssstatic
__sssstatic __sssstatic __sssstatic __sssstatic
<center><img src="https://git.le-club-des-sans-sujets.org/gauthiier/__sssstatic/raw/commit/038b5a6bf18aba7f5998d00077ce567b87cbe699/styles/+++/david-gauthier.jpg" /></center>
[directory/file-based generation of static www pages for https://davidgauthier.info]
+65 -38
View File
@@ -1,50 +1,67 @@
#!/usr/bin/env python
import argparse, json, sys, markdown, shutil, json, re, pathlib, shutil
import utils.imgconv
input_dir = None
output_dir = None
style = None
(W, H, FMT) = (None, None, None)
codebase = pathlib.Path(__file__).parent.absolute()
def translate_index_header(txt, dirname):
href = None
sections = txt.count('- - -');
sections = txt.count('- - -')
if sections == 0:
# not following the normal template -> direct html
txt = txt.replace('data/', dirname + '/'); #<--- replace reference to data/
txt = txt.replace('data/', dirname + '/') #<--- replace reference to data/
return txt
elif sections == 1:
[text, link] = txt.split('- - -');
elif sections == 2:
[text, link, href] = txt.split('- - -');
[text, link] = txt.split('- - -')
text_md = markdown.markdown(text);
link_md = markdown.markdown(link);
# revise this - perhaps with a better
link_md = link_md.replace('data/', dirname + '/');
text_md = markdown.markdown(text)
link_info = json.loads(link)
dirpath = pathlib.Path(dirname)
img_name = pathlib.Path(link_info['img']).name
img_path = dirpath / img_name
img_resize_path = dirpath / "img-resize" / img_name
picture_el = emit_picture(str(img_path), str(img_resize_path))
table = codebase / "templates/<table>"
with table.open(encoding="utf-8") as fp:
out = fp.read()
out = out.replace('[[text_md]]', text_md);
out = out.replace('[[link_md]]', link_md);
if href:
href = href.replace('data/', dirname + '/');
out = "<a " + href + ">" + out + "</a>";
out = out.replace('[[link_md]]', picture_el);
if link_info['href']:
if link_info['href'] == "data":
href = dirname + "/"
else:
href = link_info['href']
out = "<a href='" + href + "'>" + out + "</a>";
return out
def escape_date(dirname):
return re.sub('^20\d{2}?.', '', dirname)
def emit_picture(src_full, src_resize):
return f'''<picture>
<source media="(max-width: 799px)" srcset="{src_resize}" />
<source media="(min-width: 800px)" srcset="{src_full}" />
<img src="{src_full}" />
</picture>'''
def emit_img(file: pathlib.Path, data_dir: pathlib.Path):
## this is where LOD can be applied
resize_dir = data_dir / "img-resize"
resize_dir.mkdir(parents=True, exist_ok=True)
filepath = data_dir / file
resize_file = utils.imgconv.convert(filepath, (W, H, FMT), resize_dir)
return f'<a href="{file}"><img src="{file}" /></a>'
return f'<a href="{file}">' + emit_picture(str(file), "img-resize/" + resize_file.name) + '</a>'
def emit_video_mp4(file: pathlib.Path, data_dir: pathlib.Path):
return f'<video controls><source src="{file}" type="video/mp4"</video>'
@@ -53,7 +70,9 @@ def emit_audio(file: pathlib.Path, data_dir: pathlib.Path, full=False):
# an '.audio' file is a json file with a list of audio elements
# which need to be bundles as a type of list in a single <li>
file = data_dir / file;
if not file.is_file():
file = data_dir / file;
if file.is_file():
with file.open() as fp:
audio = json.loads(fp.read())
@@ -93,6 +112,7 @@ def default(file, data_dir):
content_map = {
'.png': emit_img,
'.jpg': emit_img,
'.jpeg': emit_img,
'.m4v': emit_video_mp4,
'.mov': emit_video_mp4,
'.mp4': emit_video_mp4,
@@ -123,10 +143,11 @@ def index_content(dir_name: str, data_dir: pathlib.Path, index_txt: pathlib.Path
if desc_md is None and content_index is None:
return;
content_desc = ""
content = ""
if desc_md:
content += "<li>" + "<desc>" + "\n" + desc_md + "</desc>" + "</li>" + "\n";
content_desc += "<li>" + "<desc>" + "\n" + desc_md + "</desc>" + "</li>" + "\n";
if content_index:
@@ -134,21 +155,24 @@ def index_content(dir_name: str, data_dir: pathlib.Path, index_txt: pathlib.Path
for i in content_index:
f = data_dir / i
if f.is_file():
files.append(i);
files.append(data_dir / i);
else:
files += [pathlib.Path(a.name) for a in list(data_dir.glob(i))]
# sort files?
files.sort()
for j in files:
for j in files:
ext = j.suffix.lower()
if ext in content_map:
element = content_map[ext](j, data_dir);
if element:
content += "<li>" + element + "</li>" + "\n";
html = template.replace('[[content]]', content).replace('[[dir]]', str(dir_name));
# check if there is an html file existing already. if so use that one.
html = template.replace('[[content_desc]]', content_desc).replace('[[content]]', content).replace('[[dir]]', str(dir_name));
try:
out = data_dir / 'index.html'
@@ -180,6 +204,7 @@ if __name__ == '__main__':
p.add_argument('--output', "-o", help='output directory');
p.add_argument('--style', "-y", default="+++", help='css style, ico, etc.');
p.add_argument("--settings", "-s", default=".static/settings.json", help="Settings file (default: .static/settings.json")
p.add_argument('--format', '-f', default="1000x1000", help='img output formats (ex. 1000x)');
p.add_argument('--clean', help='cleans the output directory');
args = p.parse_args();
@@ -201,15 +226,20 @@ if __name__ == '__main__':
if inputdir is not None:
input_dir = inputdir;
else:
print(f"Input directory {args.input} is not a directory... Aborting.")
sys.exit(1)
sys.exit(f"Input directory {args.input} is not a directory... Aborting.")
if args.output:
outputdir = check_dir_exists(args.output, create=True)
if outputdir is not None:
output_dir = outputdir;
else:
print(f"Output directory {args.output} is not a directory... Aborting.")
sys.exit(1)
sys.exit(f"Output directory {args.output} is not a directory... Aborting.")
if args.format:
(W, H, FMT) = utils.imgconv.parse_format(args.format)
if not FMT:
sys.exit(f"Format {str(args.format)} is not valid. Aborting.")
if style is not None:
style_dir = codebase / f"styles/{style}"
@@ -217,8 +247,7 @@ if __name__ == '__main__':
style = args.style
if input_dir is None:
print(f"Error with input directory... Aborting.")
sys.exit(1)
sys.exit(f"Error with input directory... Aborting.")
if output_dir is None:
print(f"No output directory.")
@@ -236,7 +265,6 @@ if __name__ == '__main__':
except:
print(f"error erasing {output_dir}. Continuing.")
print('1/3 - Configuring');
# main index template
@@ -271,13 +299,11 @@ if __name__ == '__main__':
datadir = d / "data"
if datadir.is_dir():
section_indx_txt = datadir / "index.txt"
section_desc_txt = datadir / "desc.txt"
section_desc_txt = datadir / "desc.md"
out_index = None
if section_indx_txt.is_file() or section_desc_txt.is_file():
out_index = index_content(dirname, d, section_indx_txt, section_desc_txt, section_indx_template_str);
if out_index is None:
continue
out_index = index_content(dirname, datadir, section_indx_txt, section_desc_txt, section_indx_template_str)
if output_dir is not None:
out_datadir = output_dir / dirname
@@ -298,11 +324,12 @@ if __name__ == '__main__':
continue
# copy index after (since index.html might be lurking in content dirs)
try:
shutil.copy2(out_index, out_datadir)
except:
print(f"error copying {out_index} to {out_datadir}. Continuing.")
continue
if out_index:
try:
shutil.copy2(out_index, out_datadir)
except:
print(f"error copying {out_index} to {out_datadir}. Continuing.")
continue
print('3/3 - Generating ouput');
+2
View File
@@ -0,0 +1,2 @@
Markdown==3.4.3
Wand==0.6.11
Executable
+29
View File
@@ -0,0 +1,29 @@
#!/bin/bash
if ! [[ "$1" =~ ^(install|clean|run) ]]; then
echo "usage: $0 [action]"
echo "where action can be: [install, clean, run]"
exit 1
fi
case $1 in
install)
echo "intalling virtual environment and dependecies"
python -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install -r requirements.txt
;;
clean)
echo "cleaning up"
rm -rf venv
;;
run)
echo "running"
source venv/bin/activate
export MAGICK_HOME=/opt/homebrew/Cellar/imagemagick/7.1.1-15_1
# exec python $2 "${@:3}"
esac
+13 -51
View File
@@ -20,57 +20,19 @@
<pre>
-----BEGIN PGP PUBLIC KEY BLOCK-----
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
=rlRS
-----END PGP PUBLIC KEY BLOCK-----
</pre>
mDMEZLoz/RYJKwYBBAHaRw8BAQdAsuOzLRb5SR4kJKpiFcP3XhPYyrcm8lqJQCzq
Kgq0cau0RURhdmlkIEdhdXRoaWVyICg3ZSBzw6lyaWUsIGRlcyBtb3RzIMOpc290
w6lyaXF1ZXMpIDxkQGdhdXRoaWllci5pbmZvPoiZBBMWCgBBFiEEdUjrpohoTnvh
RwQPqCZfthzndOcFAmS6M/0CGwMFCQWjmoAFCwkIBwICIgIGFQoJCAsCBBYCAwEC
HgcCF4AACgkQqCZfthzndOex0gEAqZKLSpIX57S0EzVrpazSYbMtRppsnndvWACD
w0TdFd4A/jKxS2FCCbUeMNwSz8iRjGRYiTZtJytQ6W3SKEQlyW8CuDgEZLoz/RIK
KwYBBAGXVQEFAQEHQFI6QyMPtYSOXCbLaPxaR8jpzjg1tqJZA4vvpOVOfdZsAwEI
B4h+BBgWCgAmFiEEdUjrpohoTnvhRwQPqCZfthzndOcFAmS6M/0CGwwFCQWjmoAA
CgkQqCZfthzndOdPrAD+NgSQRfndE2d9IiFAQDP7UNbqh0e731/ktyg2mwukudUB
AM+9BMj8ZAV+2cDSlf7Muk+SCnYd/uCy1ulJ16vKYJAC
=QFke
-----END PGP PUBLIC KEY BLOCK-----</pre>
<br>
</div>
</body>
+112 -33
View File
@@ -5,70 +5,106 @@ body {
padding: 0;
}
.tableau {
border: 10px grey ridge;
margin: 5em;
margin-bottom: 1em;
hd {
display: flex;
flex-direction: column;
max-width: 45em;
min-width: 250px;
}
hd img {
width: 80%;
border: 10px grey ridge;
margin-bottom: 1em;
margin-top: 5em;
}
h1 { font-size: 2.7vw; }
h2 { font-size: 2.2vw;}
h3 { font-size: 1.7vw;}
h4 { font-size: 1.3vw;}
table {
display: block;
margin: 1em;
border: 10px grey ridge;
font-size: small;
text-align: left;
width: 55em;
max-width: 55em;
min-width: 250px;
}
table td {
border: 2px grey ridge;
table tr {
display: flex;
flex-direction: column;
text-align: center;
}
table tr td {
padding: 1em;
/* width: 75em;*/
}
table td h1 {
bborder: 1px red solid;
margin-top: 0.4em;
margin-bottom: 0.2em;
}
table tr td img {
width: 100%;
height: auto;
border: 2px grey ridge;
}
table tr td video {
width: 100%;
height: auto;
border: 2px grey ridge;
}
table td p {
bborder: 1px red solid;
margin-top: 0.1em;
margin-bottom: 0.4em;
}
table tr {
text-align: center;
h1 a:hover, h1 a:active {
text-decoration: none;
}
table td img {
width: 100%;
border: 2px grey ridge;
a:hover p, a:active p {
text-decoration: none;
}
.lst {
display: flex;
flex-direction: column;
margin-right: 3em;
margin-left: 3em;
}
.lst p mat {
margin-left: : 2em;
}
.lst ul li { display: inline; }
.lst ul li desc {
margin: 2em;
margin-left: 1em;
margin-right: 1em;
margin-bottom: 1em;
width: 985;
min-width: 250px;
max-width: 1024px;
display: block;
}
.lst ul li desc img {
border: 10px grey ridge;
margin: 0em;
margin-bottom: 2em;
width: 985;
width: 98%;
display: block;
}
@@ -76,36 +112,42 @@ table td img {
border: 10px grey ridge;
margin: 0em;
margin-bottom: 2em;
width: 985;
width: 98%;
display: block;
}
.lst ul li { display: inline-block; }
.lst ul li img {
border: 10px grey ridge;
margin: 2em;
margin: 0.5em;
margin-bottom: 1em;
width: 450;
resize: both;
overflow: auto;
width: 488px;
}
.lst ul li video {
border: 10px grey ridge;
margin: 2em;
margin: 0.5em;
margin-bottom: 1em;
width: 450;
width: 488px;
}
.lst ul li sound {
display: inline-block;
display: block;
border: 10px grey ridge;
margin: 2em;
width: 440;
margin-left: 1em;
margin-right: 1em;
padding: 10;
min-width: 250px;
max-width: 990px;
}
.lst ul li sound track {
display: block;
margin-top: 0.3em;
margin-bottom: 0.3em;
width: 100%;
}
.lst ul li sound info {
@@ -117,19 +159,19 @@ table td img {
margin-top: 0.5em;
}
.lst ul li lo img {
.lst ul li desc lo img {
border: none;
margin: 1em;
margin-top: 0.5em;
max-width: 300;
}
.lst ul li la img {
.lst ul li desc la img {
border: none;
margin: 1em;
margin-top: 0.5em;
max-width: 100;
max-height: 100;
min-width: 100;
}
address {
@@ -140,4 +182,41 @@ address {
margin: 20px;
}
@media screen and (max-width: 1200px) {
h1 { font-size: 6vw; }
h2 { font-size: 5.3vw;}
h3 { font-size: 5vw;}
h4 { font-size: 4vw;}
p { font-size: 3.7vw;}
pre { font-size: 3.5vw;}
table {
max-width: 65em;
}
.lst ul li { display: block; }
.lst ul li img {
border: 10px grey ridge;
margin: 0.5em;
margin-bottom: 1em;
width: 96%;
min-width: 250px;
}
.lst ul li video {
border: 10px grey ridge;
margin: 0.5em;
margin-bottom: 1em;
width: 96%;
min-width: 250px;
}
}
+4 -1
View File
@@ -15,8 +15,11 @@
<div class="lst">
<ul>
[[content]]
[[content_desc]]
</ul>
<ul>
[[content]]
</ul>
</div>
<address>Apache Server at gauthiier.info Port 80</address>
+7 -9
View File
@@ -1,22 +1,20 @@
<html>
<head>
<meta charset="utf-8">
<meta name="keywords" content="david gauthier, gauthiier, davidgauthier, dviid">
<meta name="keywords" content="david gauthier, gauthiier, davidgauthier">
<meta name="description" content="David Gauthier (b.1979, CA) - selected index of works">
<link rel="icon" href="+++/jules-henri.ico" type="image/x-icon">
<link rel="stylesheet" type="text/css" href="+++/lestyle.css"/>
<link rel="pgpkey" href="+++/key.asc"/>
<link rel="openid.delegate" href="http://gauthiier.info/" />
<link rel="openid.server" href="https://indieauth.com/openid" />
<title>David Gauthier</title>
</head>
<body>
<div align="center">
<a href="+++/"><img src="+++/yeux.png" width="500" class="tableau"></a>
<h4>David Gauthier</h4>
<h1><i>(Selected) Index of works</i></h1>
<h4><a href="https://www.uu.nl/medewerkers/DGauthier">index of academic work</a></h4>
<h4>d[at]gauthiier.info</h4>
<hd>
<a href="+++/"><img src="+++/yeux.png" class="tableau"></a>
<h3>David Gauthier</h3>
<h1><i>(Selected) Index of works</i></h1>
<h3><a href="https://www.uu.nl/staff/DGauthier">index of academic work</a></h3>
</hd>
[[content]]
</div>
</body>
+82
View File
@@ -0,0 +1,82 @@
import argparse, pathlib, subprocess, sys
from wand.image import Image
supported_glob = "[jpJP][npNP][egEG]"
def sanity_check_system():
r = subprocess.call("magick -version", shell=True) == 0
if not r:
sys.exit("ImageMagick not installed. Aborting...")
def parse_format(format_str):
fmt = format_str.lower()
if 'x' in fmt:
w_h = fmt.split('x')
w = int(w_h[0]) if w_h[0] != '' else 0
h = int(w_h[1]) if w_h[1] != '' else 0
return(w, h, fmt)
return (None, None, None)
def convert(filepath : pathlib.Path, fmt : tuple, output_dir: pathlib.Path):
(w, h, f) = fmt
# img exists?
output = output_dir / filepath.name
if output.exists() and output.is_file():
with Image(filename=str(output)) as img:
if w > 0 and img.width == w or h > 0 and img.height == h:
return output
with Image(filename=str(filepath)) as img:
print(f". converting {filepath}")
print(f" > {img.size}")
img.resolution = (72, 72)
if w > 0 and img.width > w or h > 0 and img.height > h:
img.transform(resize=f)
print(f" > {img.size}")
img.save(filename=str(output))
return output
def convert_all(input_dir: pathlib.Path, fmt : tuple, output_dir: pathlib.Path):
img_files = input_dir.glob("*." + supported_glob + "*")
for i in img_files:
convert(i, fmt, output_dir)
if __name__ == '__main__':
p = argparse.ArgumentParser(description='Converts images files to other formats (using wand/ImageMagick)');
p.add_argument('-i', '--input', help='input directory');
p.add_argument('-o', '--output', help='output directory');
p.add_argument('-f', '--format', help='output formats (ex. 1000x)');
sanity_check_system()
args = p.parse_args()
if not args.format:
sys.exit("No formats specified. Aborting.")
input_dir = pathlib.Path(".")
if args.input:
input_dir = pathlib.Path(args.input)
if not input_dir.exists() or not input_dir.is_dir():
sys.exit(f"Input {str(input_dir)} is not a directory. Aborting.")
output_dir = input_dir / "img-resize"
if args.output:
output_dir = pathlib.Path(args.output)
output_dir.mkdir(parents=True, exist_ok=True)
(w, h, fmt) = parse_format(args.format)
if not fmt:
sys.exit(f"Format {str(args.format)} is not valid. Aborting.")
img_files = input_dir.glob("*." + supported_glob + "*")
for i in img_files:
convert(i, (w, h, fmt), output_dir)