Compare commits
	
		
			3 Commits
		
	
	
		
			683d152491
			...
			cc64d3012a
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cc64d3012a | |||
| 86363d4c2f | |||
| 0ee3a22b80 | 
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,3 @@
 | 
			
		||||
venv
 | 
			
		||||
*.pyc
 | 
			
		||||
*.pyc
 | 
			
		||||
output
 | 
			
		||||
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
								
							@ -4,23 +4,17 @@ Just a simple python program to generate static site
 | 
			
		||||
 | 
			
		||||
## File
 | 
			
		||||
 | 
			
		||||
- .nef: **(MANDATORY)**
 | 
			
		||||
- .pp3: (optionnal)
 | 
			
		||||
- .png: high resolution format (optionnal: can be generated by the .nef)
 | 
			
		||||
- .jpeg: low resolution format (optionnal: can be generated by the .png)
 | 
			
		||||
- desc.md: description markdown file (optionnal)
 | 
			
		||||
- RAW: (optionnal)
 | 
			
		||||
- EDIT_DATA: (optionnal)
 | 
			
		||||
- LARGE: high resolution format (optionnal: can be generated by the RAW)
 | 
			
		||||
- SMALL: low resolution format (optionnal: can be generated by the LARGE)
 | 
			
		||||
- DESQ: description markdown file (optionnal)
 | 
			
		||||
 | 
			
		||||
### File structure
 | 
			
		||||
### Format supported
 | 
			
		||||
```
 | 
			
		||||
img1/
 | 
			
		||||
├─ img1.nef
 | 
			
		||||
img2/
 | 
			
		||||
├─ img2.pp3
 | 
			
		||||
├─ img2.png
 | 
			
		||||
├─ img2.jpeg
 | 
			
		||||
├─ img2.nef
 | 
			
		||||
img3.nef
 | 
			
		||||
img4.png
 | 
			
		||||
img4.jpeg
 | 
			
		||||
img4.nef
 | 
			
		||||
RAW: .NEF
 | 
			
		||||
LARGE: .png
 | 
			
		||||
SMALL: jpeg
 | 
			
		||||
EDIT_DATA: .pp3
 | 
			
		||||
DESQ: .md
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										9
									
								
								config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								config.json
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
{
 | 
			
		||||
    "file_type_extensions": {
 | 
			
		||||
        "raw": [".NEF"],
 | 
			
		||||
        "large": [".png"],
 | 
			
		||||
        "small": [".jpeg"],
 | 
			
		||||
        "edits": [".pp3"],
 | 
			
		||||
        "desq": [".md"]
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,55 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="fr">
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 | 
			
		||||
    <title>Dropdown Button</title>
 | 
			
		||||
    <style>
 | 
			
		||||
        /* Style du bouton */
 | 
			
		||||
        .dropdown-btn {
 | 
			
		||||
            padding: 10px 20px;
 | 
			
		||||
            background-color: #4CAF50;
 | 
			
		||||
            color: white;
 | 
			
		||||
            border: none;
 | 
			
		||||
            cursor: pointer;
 | 
			
		||||
            font-size: 16px;
 | 
			
		||||
            border-radius: 5px;
 | 
			
		||||
            display: inline-block;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Cacher le radio (pour qu'il ne soit pas visible) */
 | 
			
		||||
        .dropdown-radio {
 | 
			
		||||
            display: none;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Style du texte qui apparaît lorsque la case est cochée */
 | 
			
		||||
        .dropdown-text {
 | 
			
		||||
            display: none;
 | 
			
		||||
            margin-top: 10px;
 | 
			
		||||
            padding: 10px;
 | 
			
		||||
            background-color: #f1f1f1;
 | 
			
		||||
            border: 1px solid #ddd;
 | 
			
		||||
            border-radius: 5px;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* Quand le radio est sélectionné, afficher le texte */
 | 
			
		||||
        .dropdown-radio:checked + .dropdown-btn + .dropdown-text {
 | 
			
		||||
            display: block;
 | 
			
		||||
        }
 | 
			
		||||
    </style>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
    <!-- Radio caché qui contrôle l'affichage du texte -->
 | 
			
		||||
    <input type="radio" id="dropdown" class="dropdown-radio" name="dropdown-group">
 | 
			
		||||
 | 
			
		||||
    <!-- Bouton -->
 | 
			
		||||
    <label for="dropdown" class="dropdown-btn">Afficher le texte</label>
 | 
			
		||||
 | 
			
		||||
    <!-- Texte qui se déploie -->
 | 
			
		||||
    <div class="dropdown-text">
 | 
			
		||||
        Voici le texte qui se déploie quand on clique sur le bouton.
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										5
									
								
								src/filename.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								src/filename.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
LARGE = "*.png"
 | 
			
		||||
SMALL = "*.jpeg"
 | 
			
		||||
RAW = "*.nef"
 | 
			
		||||
EDIT = "*.pp3"
 | 
			
		||||
DESC = "*.md"
 | 
			
		||||
							
								
								
									
										97
									
								
								src/main.py
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								src/main.py
									
									
									
									
									
								
							@ -1,14 +1,103 @@
 | 
			
		||||
import sys
 | 
			
		||||
import help
 | 
			
		||||
import PIL
 | 
			
		||||
import rawpy
 | 
			
		||||
import imageio
 | 
			
		||||
import os
 | 
			
		||||
import shutil
 | 
			
		||||
import json
 | 
			
		||||
from PIL import Image
 | 
			
		||||
from jinja2 import Environment, FileSystemLoader
 | 
			
		||||
import subprocess
 | 
			
		||||
 | 
			
		||||
with open('config.json', 'r') as file:
 | 
			
		||||
    config: dict = json.load(file)
 | 
			
		||||
 | 
			
		||||
# Initialiser l'environnement avec un dossier de templates
 | 
			
		||||
env = Environment(loader=FileSystemLoader('src/templates'))
 | 
			
		||||
 | 
			
		||||
template = env.get_template('index.html')
 | 
			
		||||
 | 
			
		||||
def get_files_recursive(directory):
 | 
			
		||||
    file_paths = []
 | 
			
		||||
    for root, dirs, files in os.walk(directory):
 | 
			
		||||
        for file in files:
 | 
			
		||||
            file_paths.append(os.path.join(root, file))
 | 
			
		||||
    return file_paths
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def move_files(files: list[str], input_path, output_path):
 | 
			
		||||
    for key, type_file_extensions in config["file_type_extensions"].items():
 | 
			
		||||
        for file in files:
 | 
			
		||||
            for type_file_extension in type_file_extensions:
 | 
			
		||||
                if file.endswith(type_file_extension):
 | 
			
		||||
                    path = file.replace(input_path, output_path)[:-len(type_file_extension)]
 | 
			
		||||
                    if not os.path.exists(path):
 | 
			
		||||
                        if (key not in ["raw", "large", "small"]):
 | 
			
		||||
                            continue
 | 
			
		||||
                        os.makedirs(path)
 | 
			
		||||
                    shutil.copy2(file, path)
 | 
			
		||||
 | 
			
		||||
def nef_to_jpeg(path:str):
 | 
			
		||||
    with rawpy.imread(path) as raw:
 | 
			
		||||
        rgb = raw.postprocess()
 | 
			
		||||
        imageio.imwrite(path.replace('.NEF', '.jpeg'), rgb)
 | 
			
		||||
 | 
			
		||||
def png_to_jpeg(path: str):
 | 
			
		||||
    im = Image.open(path)
 | 
			
		||||
    rgb_im = im.convert('RGB')
 | 
			
		||||
    rgb_im.save(path.replace('.nef', '.jpeg'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_missing_images(raws: list[str], large: list[str], small: list[str]):
 | 
			
		||||
    if len(small) == 0:
 | 
			
		||||
        if (len(large) == 0):
 | 
			
		||||
            nef_to_jpeg(raws[0])
 | 
			
		||||
            return
 | 
			
		||||
        png_to_jpeg(large[0])
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
def get_exif(raws: list[str]):
 | 
			
		||||
    if (len(raws) == 0):
 | 
			
		||||
        return None
 | 
			
		||||
    return str(subprocess.check_output(["exiftool", f"{raws[0]}"])).replace("\\n", "\n")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def generate_page(output_path: str):
 | 
			
		||||
    for folder in os.listdir(output_path):
 | 
			
		||||
        path = os.path.join(output_path, folder)
 | 
			
		||||
        if (os.path.isdir(path)):
 | 
			
		||||
            files: list[str] = [os.path.join(path, file) for file in os.listdir(path) if os.path.isfile(os.path.join(path, file))]
 | 
			
		||||
            
 | 
			
		||||
            raws = [file for ext in config["file_type_extensions"]["raw"] for file in files if file.endswith(ext)]
 | 
			
		||||
            larges = [file for ext in config["file_type_extensions"]["large"] for file in files if file.endswith(ext)]
 | 
			
		||||
            smalls = [file for ext in config["file_type_extensions"]["small"] for file in files if file.endswith(ext)]
 | 
			
		||||
            
 | 
			
		||||
            generate_missing_images(raws, larges, smalls)
 | 
			
		||||
            
 | 
			
		||||
            exif = get_exif(raws)
 | 
			
		||||
            raw = os.path.basename(raws[0]) if len(raws) > 0 else None
 | 
			
		||||
            large = os.path.basename(larges[0]) if len(larges) > 0 else None
 | 
			
		||||
            small = os.path.basename(smalls[0]) if len(smalls) > 0 else None
 | 
			
		||||
 | 
			
		||||
            html_rendered = template.render(exif=exif, raw=raw, large=large, small=small)
 | 
			
		||||
 | 
			
		||||
            with open(os.path.join(path, f"{folder}.html"), "w") as f:
 | 
			
		||||
                f.write(html_rendered)
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
 | 
			
		||||
    if len(sys.argv) != 2:
 | 
			
		||||
    if len(sys.argv) < 2:
 | 
			
		||||
        help.display(sys.argv[0])
 | 
			
		||||
        return
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    input_path = sys.argv[1]
 | 
			
		||||
    output_path = "output/" if (len(sys.argv) == 2) else sys.argv[2] + "/"
 | 
			
		||||
 | 
			
		||||
    files: list[str] = get_files_recursive(input_path)
 | 
			
		||||
 | 
			
		||||
    move_files(files, input_path, output_path)
 | 
			
		||||
 | 
			
		||||
    generate_page(output_path)
 | 
			
		||||
 | 
			
		||||
if (__name__ == "__main__"):
 | 
			
		||||
    main()
 | 
			
		||||
@ -1,9 +0,0 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
    </head>
 | 
			
		||||
 | 
			
		||||
    <body>
 | 
			
		||||
        <img src="./img1.je">
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										46
									
								
								src/templates/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/templates/index.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,46 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <link rel="stylesheet" href="img1.css">
 | 
			
		||||
    </head>
 | 
			
		||||
 | 
			
		||||
    <body>
 | 
			
		||||
        <img id="small" src="{{ small }}">\
 | 
			
		||||
        {% if large or raw %}
 | 
			
		||||
        <div id="download">
 | 
			
		||||
            {% if large %}
 | 
			
		||||
            <a id="large" href="{{ large }}">
 | 
			
		||||
                <img src="../icons/file.png">
 | 
			
		||||
                <p>large</p>
 | 
			
		||||
            </a>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
            {% if raw %}
 | 
			
		||||
            <a id="raw" href="{{ raw }}">
 | 
			
		||||
                <img src="../icons/file.png">
 | 
			
		||||
                <p>raw</p>
 | 
			
		||||
            </a>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% if desc %}
 | 
			
		||||
        <div id="description">
 | 
			
		||||
        </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% if exif %}
 | 
			
		||||
        <div id="exif">
 | 
			
		||||
            <!-- Checkbox cachée qui contrôle l'affichage du texte -->
 | 
			
		||||
            <input type="checkbox" id="dropdown" class="dropdown-checkbox">
 | 
			
		||||
 | 
			
		||||
            <!-- Bouton -->
 | 
			
		||||
            <label for="dropdown" class="dropdown-btn">Display exif data</label>
 | 
			
		||||
            <div class="dropdown-text">
 | 
			
		||||
                <pre>
 | 
			
		||||
                    <code>
 | 
			
		||||
                        {{exif}}
 | 
			
		||||
                    </code>
 | 
			
		||||
                </pre>
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </body>
 | 
			
		||||
</html>
 | 
			
		||||
		Reference in New Issue
	
	Block a user