Compare commits
61 Commits
683d152491
...
main
Author | SHA1 | Date | |
---|---|---|---|
a980dd8ead | |||
69023f1917 | |||
df05678ddc | |||
bb29eb2b73 | |||
c8f8698578 | |||
6236819e2b | |||
1a0391bafe | |||
c7c2cf6409 | |||
26c60c5216 | |||
6d1661131f | |||
129dfe7df9 | |||
5fc12d5d33 | |||
b895e5d85c | |||
b434d0837a | |||
b9f7090e96 | |||
fe1f7d1485 | |||
2dd1fcfb0c | |||
8c2d5df0d2 | |||
a551217592 | |||
5c773af571 | |||
d0063c2cc4 | |||
08c0129af8 | |||
de051f222d | |||
ff56bac2cd | |||
3f30154b36 | |||
b4a78a9e7d | |||
37808d6c48 | |||
70da0a2c28 | |||
bb0973917d | |||
55bc1b36d1 | |||
73dfaf4622 | |||
37a31494fc | |||
7883f8ce6b | |||
24af283c38 | |||
ca17bd2cab | |||
760bd86bf0 | |||
97f05cee5e | |||
d911dfe1cf | |||
9335107522 | |||
196ae57b2c | |||
e27bfe74ea | |||
eb94330059 | |||
9a33ba64a2 | |||
a3301572e1 | |||
b73f374625 | |||
d96eeb4bef | |||
c92fc36b40 | |||
a106770769 | |||
b5b306eb09 | |||
8a123180c5 | |||
c68f393703 | |||
637e2382b2 | |||
a4324c61d0 | |||
a5e03ae8d5 | |||
97533dc6d8 | |||
307c5c4d82 | |||
0b1e2479c1 | |||
3831d57fe6 | |||
cc64d3012a | |||
86363d4c2f | |||
0ee3a22b80 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,4 @@
|
|||||||
venv
|
venv
|
||||||
*.pyc
|
*.pyc
|
||||||
|
test_out
|
||||||
|
test_in
|
55
README.md
55
README.md
@ -1,26 +1,43 @@
|
|||||||
# PhotoHUB
|
# PhotoHUB
|
||||||
Just a simple python program to generate static site
|
Just a simple python program to generate static site
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|
### Picture Page
|
||||||
|

|
||||||
|
|
||||||
|
### Album Page
|
||||||
|

|
||||||
|
|
||||||
|
## Installation
|
||||||
|
``` sh
|
||||||
|
python3 -m venv venv
|
||||||
|
python3 -m pip -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Move and rename file
|
||||||
|
```sh
|
||||||
|
python3 tools/copy.py %your raws% %site location%
|
||||||
|
```
|
||||||
|
|
||||||
|
Generate html page
|
||||||
|
``` sh
|
||||||
|
python3 src/main.py %site location%
|
||||||
|
```
|
||||||
|
|
||||||
## File
|
## File
|
||||||
|
|
||||||
- .nef: **(MANDATORY)**
|
### Mandatory
|
||||||
- .pp3: (optionnal)
|
- a .png
|
||||||
- .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)
|
|
||||||
|
|
||||||
### File structure
|
### Optionnal
|
||||||
```
|
- raw {*.NEF}
|
||||||
img1/
|
- readme.md
|
||||||
├─ img1.nef
|
- (png file).out.pp3
|
||||||
img2/
|
|
||||||
├─ img2.pp3
|
### Futur update
|
||||||
├─ img2.png
|
- add gimp profile file
|
||||||
├─ img2.jpeg
|
- unrepertoried page
|
||||||
├─ img2.nef
|
- add audio file on page
|
||||||
img3.nef
|
|
||||||
img4.png
|
|
||||||
img4.jpeg
|
|
||||||
img4.nef
|
|
||||||
```
|
|
44
config/default.conf
Normal file
44
config/default.conf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
server_name localhost;
|
||||||
|
|
||||||
|
#access_log /var/log/nginx/host.access.log main;
|
||||||
|
|
||||||
|
location / {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
index index.html index.htm;
|
||||||
|
autoindex on;
|
||||||
|
}
|
||||||
|
|
||||||
|
#error_page 404 /404.html;
|
||||||
|
|
||||||
|
# redirect server error pages to the static page /50x.html
|
||||||
|
#
|
||||||
|
error_page 500 502 503 504 /50x.html;
|
||||||
|
location = /50x.html {
|
||||||
|
root /usr/share/nginx/html;
|
||||||
|
}
|
||||||
|
|
||||||
|
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
|
||||||
|
#
|
||||||
|
#location ~ \.php$ {
|
||||||
|
# proxy_pass http://127.0.0.1;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
|
||||||
|
#
|
||||||
|
#location ~ \.php$ {
|
||||||
|
# root html;
|
||||||
|
# fastcgi_pass 127.0.0.1:9000;
|
||||||
|
# fastcgi_index index.php;
|
||||||
|
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
|
||||||
|
# include fastcgi_params;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# deny access to .htaccess files, if Apache's document root
|
||||||
|
# concurs with nginx's one
|
||||||
|
#
|
||||||
|
#location ~ /\.ht {
|
||||||
|
# deny all;
|
||||||
|
#}
|
||||||
|
}
|
10
docker-compose.yml
Normal file
10
docker-compose.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
my-pictures:
|
||||||
|
image: nginx
|
||||||
|
volumes:
|
||||||
|
- ./test_out:/usr/share/nginx/html
|
||||||
|
- ./config:/etc/nginx/conf.d/
|
||||||
|
ports:
|
||||||
|
- 8089:80
|
||||||
|
networks: {}
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
@ -1,84 +0,0 @@
|
|||||||
body {
|
|
||||||
background-color: #002b36;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center; /* Centre l'image */
|
|
||||||
align-items: center; /* Aligne verticalement */
|
|
||||||
position: relative;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
#small {
|
|
||||||
max-width: 100%;
|
|
||||||
height: auto;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#download {
|
|
||||||
background-color: lightgray;
|
|
||||||
position: absolute;
|
|
||||||
margin: 10px;
|
|
||||||
right: 200px;
|
|
||||||
top: 200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#download * {
|
|
||||||
background-color: aqua;
|
|
||||||
display: flex;
|
|
||||||
margin: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#download * p {
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#download img {
|
|
||||||
height: 50px;
|
|
||||||
width: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background: #f4f4f4;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: "Courier New", monospace;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdown-btn {
|
|
||||||
padding: 10px 20px;
|
|
||||||
background-color: #4CAF50;
|
|
||||||
color: white;
|
|
||||||
border: none;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Cacher le checkbox (pour qu'il ne soit pas visible) */
|
|
||||||
.dropdown-checkbox {
|
|
||||||
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 la case est cochée, afficher le texte */
|
|
||||||
.dropdown-checkbox:checked + .dropdown-btn + .dropdown-text {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
@ -1,38 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<link rel="stylesheet" href="img1.css">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<img id="small" src="./img1.jpeg">
|
|
||||||
<div id="download">
|
|
||||||
<a id="large" href="./img1.png">
|
|
||||||
<img src="../icons/file.png">
|
|
||||||
<p>large</p>
|
|
||||||
</a>
|
|
||||||
<a id="raw" href="./img1.NEF">
|
|
||||||
<img src="../icons/file.png">
|
|
||||||
<p>raw</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<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>
|
|
||||||
ExifTool Version Number : 12.57
|
|
||||||
File Name : img1.NEF
|
|
||||||
Directory : ./example/img1
|
|
||||||
File Size : 5.7 MB
|
|
||||||
</code>
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
Binary file not shown.
Before Width: | Height: | Size: 35 KiB |
Binary file not shown.
Before Width: | Height: | Size: 208 KiB |
@ -1,752 +0,0 @@
|
|||||||
[Version]
|
|
||||||
AppVersion=5.9
|
|
||||||
Version=349
|
|
||||||
|
|
||||||
[General]
|
|
||||||
Rank=0
|
|
||||||
ColorLabel=0
|
|
||||||
InTrash=false
|
|
||||||
|
|
||||||
[Exposure]
|
|
||||||
Auto=false
|
|
||||||
Clip=0.02
|
|
||||||
Compensation=0
|
|
||||||
Brightness=0
|
|
||||||
Contrast=0
|
|
||||||
Saturation=0
|
|
||||||
Black=0
|
|
||||||
HighlightCompr=0
|
|
||||||
HighlightComprThreshold=0
|
|
||||||
ShadowCompr=50
|
|
||||||
HistogramMatching=true
|
|
||||||
CurveFromHistogramMatching=true
|
|
||||||
ClampOOG=true
|
|
||||||
CurveMode=FilmLike
|
|
||||||
CurveMode2=Standard
|
|
||||||
Curve=4;0;0;0.050000000000000003;0.026486708211773232;0.12;0.076991901310519445;0.21799999999999997;0.19406184409178534;0.35519999999999996;0.40643555161187844;0.54727999999999999;0.65396579527439191;0.81619199999999992;0.86925799088009603;1;1;
|
|
||||||
Curve2=0;
|
|
||||||
|
|
||||||
[HLRecovery]
|
|
||||||
Enabled=true
|
|
||||||
Method=Blend
|
|
||||||
Hlbl=0
|
|
||||||
|
|
||||||
[Retinex]
|
|
||||||
Enabled=false
|
|
||||||
Str=20
|
|
||||||
Scal=3
|
|
||||||
Iter=1
|
|
||||||
Grad=1
|
|
||||||
Grads=1
|
|
||||||
Gam=1.3
|
|
||||||
Slope=3
|
|
||||||
Median=false
|
|
||||||
Neigh=80
|
|
||||||
Offs=0
|
|
||||||
Vart=200
|
|
||||||
Limd=8
|
|
||||||
highl=4
|
|
||||||
skal=3
|
|
||||||
complexMethod=normal
|
|
||||||
RetinexMethod=high
|
|
||||||
mapMethod=none
|
|
||||||
viewMethod=none
|
|
||||||
Retinexcolorspace=Lab
|
|
||||||
Gammaretinex=none
|
|
||||||
CDCurve=0;
|
|
||||||
MAPCurve=0;
|
|
||||||
CDHCurve=0;
|
|
||||||
LHCurve=0;
|
|
||||||
Highlights=0
|
|
||||||
HighlightTonalWidth=80
|
|
||||||
Shadows=0
|
|
||||||
ShadowTonalWidth=80
|
|
||||||
Radius=40
|
|
||||||
TransmissionCurve=1;0;0.5;0.34999999999999998;0.34999999999999998;0.59999999999999998;0.75;0.34999999999999998;0.34999999999999998;1;0.5;0.34999999999999998;0.34999999999999998;
|
|
||||||
GainTransmissionCurve=1;0;0.10000000000000001;0.34999999999999998;0;0.25;0.25;0.34999999999999998;0.34999999999999998;0.69999999999999996;0.25;0.34999999999999998;0.34999999999999998;1;0.10000000000000001;0;0;
|
|
||||||
|
|
||||||
[Local Contrast]
|
|
||||||
Enabled=false
|
|
||||||
Radius=80
|
|
||||||
Amount=0.20000000000000001
|
|
||||||
Darkness=1
|
|
||||||
Lightness=1
|
|
||||||
|
|
||||||
[Channel Mixer]
|
|
||||||
Enabled=false
|
|
||||||
Red=1000;0;0;
|
|
||||||
Green=0;1000;0;
|
|
||||||
Blue=0;0;1000;
|
|
||||||
|
|
||||||
[Black & White]
|
|
||||||
Enabled=false
|
|
||||||
Method=Desaturation
|
|
||||||
Auto=false
|
|
||||||
ComplementaryColors=true
|
|
||||||
Setting=RGB-Rel
|
|
||||||
Filter=None
|
|
||||||
MixerRed=33
|
|
||||||
MixerOrange=33
|
|
||||||
MixerYellow=33
|
|
||||||
MixerGreen=33
|
|
||||||
MixerCyan=33
|
|
||||||
MixerBlue=33
|
|
||||||
MixerMagenta=33
|
|
||||||
MixerPurple=33
|
|
||||||
GammaRed=0
|
|
||||||
GammaGreen=0
|
|
||||||
GammaBlue=0
|
|
||||||
Algorithm=SP
|
|
||||||
LuminanceCurve=0;
|
|
||||||
BeforeCurveMode=Standard
|
|
||||||
AfterCurveMode=Standard
|
|
||||||
BeforeCurve=0;
|
|
||||||
AfterCurve=0;
|
|
||||||
|
|
||||||
[Luminance Curve]
|
|
||||||
Enabled=false
|
|
||||||
Brightness=0
|
|
||||||
Contrast=0
|
|
||||||
Chromaticity=0
|
|
||||||
AvoidColorShift=false
|
|
||||||
RedAndSkinTonesProtection=0
|
|
||||||
LCredsk=true
|
|
||||||
LCurve=0;
|
|
||||||
aCurve=0;
|
|
||||||
bCurve=0;
|
|
||||||
ccCurve=0;
|
|
||||||
chCurve=0;
|
|
||||||
lhCurve=0;
|
|
||||||
hhCurve=0;
|
|
||||||
LcCurve=0;
|
|
||||||
ClCurve=0;
|
|
||||||
|
|
||||||
[Sharpening]
|
|
||||||
Enabled=false
|
|
||||||
Contrast=20
|
|
||||||
Method=usm
|
|
||||||
Radius=0.5
|
|
||||||
BlurRadius=0.20000000000000001
|
|
||||||
Amount=200
|
|
||||||
Threshold=20;80;2000;1200;
|
|
||||||
OnlyEdges=false
|
|
||||||
EdgedetectionRadius=1.8999999999999999
|
|
||||||
EdgeTolerance=1800
|
|
||||||
HalocontrolEnabled=false
|
|
||||||
HalocontrolAmount=85
|
|
||||||
DeconvRadius=0.75
|
|
||||||
DeconvAmount=100
|
|
||||||
DeconvDamping=0
|
|
||||||
DeconvIterations=30
|
|
||||||
|
|
||||||
[Vibrance]
|
|
||||||
Enabled=false
|
|
||||||
Pastels=0
|
|
||||||
Saturated=0
|
|
||||||
PSThreshold=0;75;
|
|
||||||
ProtectSkins=false
|
|
||||||
AvoidColorShift=true
|
|
||||||
PastSatTog=true
|
|
||||||
SkinTonesCurve=0;
|
|
||||||
|
|
||||||
[SharpenEdge]
|
|
||||||
Enabled=false
|
|
||||||
Passes=2
|
|
||||||
Strength=50
|
|
||||||
ThreeChannels=false
|
|
||||||
|
|
||||||
[SharpenMicro]
|
|
||||||
Enabled=false
|
|
||||||
Matrix=false
|
|
||||||
Strength=20
|
|
||||||
Contrast=20
|
|
||||||
Uniformity=5
|
|
||||||
|
|
||||||
[White Balance]
|
|
||||||
Enabled=true
|
|
||||||
Setting=Camera
|
|
||||||
Temperature=5098
|
|
||||||
Green=1.0387654687995256
|
|
||||||
Equal=1
|
|
||||||
TemperatureBias=0
|
|
||||||
|
|
||||||
[Color appearance]
|
|
||||||
Enabled=false
|
|
||||||
Degree=90
|
|
||||||
AutoDegree=true
|
|
||||||
Degreeout=90
|
|
||||||
AutoDegreeout=true
|
|
||||||
Surround=Average
|
|
||||||
complex=normal
|
|
||||||
ModelCat=16
|
|
||||||
CatCat=clas
|
|
||||||
Surrsrc=Average
|
|
||||||
AdaptLum=16
|
|
||||||
Badpixsl=0
|
|
||||||
Model=RawT
|
|
||||||
Illum=i50
|
|
||||||
Algorithm=No
|
|
||||||
J-Light=0
|
|
||||||
Q-Bright=0
|
|
||||||
C-Chroma=0
|
|
||||||
S-Chroma=0
|
|
||||||
M-Chroma=0
|
|
||||||
J-Contrast=0
|
|
||||||
Q-Contrast=0
|
|
||||||
H-Hue=0
|
|
||||||
RSTProtection=0
|
|
||||||
AdaptScene=2000
|
|
||||||
AutoAdapscen=true
|
|
||||||
YbScene=18
|
|
||||||
Autoybscen=true
|
|
||||||
SurrSource=false
|
|
||||||
Gamut=true
|
|
||||||
Tempout=5003
|
|
||||||
Autotempout=true
|
|
||||||
Greenout=1
|
|
||||||
Tempsc=5003
|
|
||||||
Greensc=1
|
|
||||||
Ybout=18
|
|
||||||
Datacie=false
|
|
||||||
Tonecie=false
|
|
||||||
Presetcat02=false
|
|
||||||
CurveMode=Lightness
|
|
||||||
CurveMode2=Brightness
|
|
||||||
CurveMode3=Chroma
|
|
||||||
Curve=0;
|
|
||||||
Curve2=0;
|
|
||||||
Curve3=0;
|
|
||||||
|
|
||||||
[Impulse Denoising]
|
|
||||||
Enabled=false
|
|
||||||
Threshold=50
|
|
||||||
|
|
||||||
[Defringing]
|
|
||||||
Enabled=false
|
|
||||||
Radius=2
|
|
||||||
Threshold=13
|
|
||||||
HueCurve=1;0.16666666699999999;0;0.34999999999999998;0.34999999999999998;0.34699999999999998;0;0.34999999999999998;0.34999999999999998;0.51366742600000004;0;0.34999999999999998;0.34999999999999998;0.66894457100000004;0;0.34999999999999998;0.34999999999999998;0.82877752459999998;0.97835991;0.34999999999999998;0.34999999999999998;0.99088838270000001;0;0.34999999999999998;0.34999999999999998;
|
|
||||||
|
|
||||||
[Dehaze]
|
|
||||||
Enabled=false
|
|
||||||
Strength=50
|
|
||||||
ShowDepthMap=false
|
|
||||||
Depth=25
|
|
||||||
Saturation=50
|
|
||||||
|
|
||||||
[Directional Pyramid Denoising]
|
|
||||||
Enabled=false
|
|
||||||
Enhance=false
|
|
||||||
Median=false
|
|
||||||
Luma=0
|
|
||||||
Ldetail=0
|
|
||||||
Chroma=15
|
|
||||||
Method=Lab
|
|
||||||
LMethod=SLI
|
|
||||||
CMethod=MAN
|
|
||||||
C2Method=AUTO
|
|
||||||
SMethod=shal
|
|
||||||
MedMethod=soft
|
|
||||||
RGBMethod=soft
|
|
||||||
MethodMed=none
|
|
||||||
Redchro=0
|
|
||||||
Bluechro=0
|
|
||||||
Gamma=1.7
|
|
||||||
Passes=1
|
|
||||||
LCurve=1;0.050000000000000003;0.14999999999999999;0.34999999999999998;0.34999999999999998;0.55000000000000004;0.040000000000000001;0.34999999999999998;0.34999999999999998;
|
|
||||||
CCCurve=1;0.050000000000000003;0.5;0.34999999999999998;0.34999999999999998;0.34999999999999998;0.050000000000000003;0.34999999999999998;0.34999999999999998;
|
|
||||||
|
|
||||||
[EPD]
|
|
||||||
Enabled=false
|
|
||||||
Strength=0.5
|
|
||||||
Gamma=1
|
|
||||||
EdgeStopping=1.3999999999999999
|
|
||||||
Scale=1
|
|
||||||
ReweightingIterates=0
|
|
||||||
|
|
||||||
[FattalToneMapping]
|
|
||||||
Enabled=false
|
|
||||||
Threshold=30
|
|
||||||
Amount=20
|
|
||||||
Anchor=50
|
|
||||||
|
|
||||||
[Shadows & Highlights]
|
|
||||||
Enabled=false
|
|
||||||
Highlights=0
|
|
||||||
HighlightTonalWidth=70
|
|
||||||
Shadows=0
|
|
||||||
ShadowTonalWidth=30
|
|
||||||
Radius=40
|
|
||||||
Lab=false
|
|
||||||
|
|
||||||
[Crop]
|
|
||||||
Enabled=false
|
|
||||||
X=-1
|
|
||||||
Y=-1
|
|
||||||
W=3032
|
|
||||||
H=2007
|
|
||||||
FixedRatio=true
|
|
||||||
Ratio=As Image
|
|
||||||
Orientation=As Image
|
|
||||||
Guide=Frame
|
|
||||||
|
|
||||||
[Coarse Transformation]
|
|
||||||
Rotate=0
|
|
||||||
HorizontalFlip=false
|
|
||||||
VerticalFlip=false
|
|
||||||
|
|
||||||
[Common Properties for Transformations]
|
|
||||||
Method=log
|
|
||||||
AutoFill=true
|
|
||||||
|
|
||||||
[Rotation]
|
|
||||||
Degree=0
|
|
||||||
|
|
||||||
[Distortion]
|
|
||||||
Amount=0
|
|
||||||
|
|
||||||
[LensProfile]
|
|
||||||
LcMode=lfauto
|
|
||||||
LCPFile=
|
|
||||||
UseDistortion=true
|
|
||||||
UseVignette=true
|
|
||||||
UseCA=false
|
|
||||||
LFCameraMake=
|
|
||||||
LFCameraModel=
|
|
||||||
LFLens=
|
|
||||||
|
|
||||||
[Perspective]
|
|
||||||
Method=simple
|
|
||||||
Horizontal=0
|
|
||||||
Vertical=0
|
|
||||||
CameraCropFactor=0
|
|
||||||
CameraFocalLength=0
|
|
||||||
CameraPitch=0
|
|
||||||
CameraRoll=0
|
|
||||||
CameraShiftHorizontal=0
|
|
||||||
CameraShiftVertical=0
|
|
||||||
CameraYaw=0
|
|
||||||
ProjectionShiftHorizontal=0
|
|
||||||
ProjectionPitch=0
|
|
||||||
ProjectionRotate=0
|
|
||||||
ProjectionShiftVertical=0
|
|
||||||
ProjectionYaw=0
|
|
||||||
ControlLineValues=
|
|
||||||
ControlLineTypes=
|
|
||||||
|
|
||||||
[Gradient]
|
|
||||||
Enabled=false
|
|
||||||
Degree=0
|
|
||||||
Feather=25
|
|
||||||
Strength=0.59999999999999998
|
|
||||||
CenterX=0
|
|
||||||
CenterY=0
|
|
||||||
|
|
||||||
[Locallab]
|
|
||||||
Enabled=false
|
|
||||||
Selspot=0
|
|
||||||
|
|
||||||
[PCVignette]
|
|
||||||
Enabled=false
|
|
||||||
Strength=0.59999999999999998
|
|
||||||
Feather=50
|
|
||||||
Roundness=50
|
|
||||||
|
|
||||||
[CACorrection]
|
|
||||||
Red=0
|
|
||||||
Blue=0
|
|
||||||
|
|
||||||
[Vignetting Correction]
|
|
||||||
Amount=0
|
|
||||||
Radius=50
|
|
||||||
Strength=1
|
|
||||||
CenterX=0
|
|
||||||
CenterY=0
|
|
||||||
|
|
||||||
[Resize]
|
|
||||||
Enabled=false
|
|
||||||
Scale=1
|
|
||||||
AppliesTo=Cropped area
|
|
||||||
Method=Lanczos
|
|
||||||
DataSpecified=3
|
|
||||||
Width=900
|
|
||||||
Height=900
|
|
||||||
LongEdge=900
|
|
||||||
ShortEdge=900
|
|
||||||
AllowUpscaling=false
|
|
||||||
|
|
||||||
[PostDemosaicSharpening]
|
|
||||||
Enabled=true
|
|
||||||
Contrast=10
|
|
||||||
AutoContrast=true
|
|
||||||
AutoRadius=true
|
|
||||||
DeconvRadius=0.75
|
|
||||||
DeconvRadiusOffset=0
|
|
||||||
DeconvIterCheck=true
|
|
||||||
DeconvIterations=20
|
|
||||||
|
|
||||||
[PostResizeSharpening]
|
|
||||||
Enabled=false
|
|
||||||
Contrast=15
|
|
||||||
Method=rld
|
|
||||||
Radius=0.5
|
|
||||||
Amount=200
|
|
||||||
Threshold=20;80;2000;1200;
|
|
||||||
OnlyEdges=false
|
|
||||||
EdgedetectionRadius=1.8999999999999999
|
|
||||||
EdgeTolerance=1800
|
|
||||||
HalocontrolEnabled=false
|
|
||||||
HalocontrolAmount=85
|
|
||||||
DeconvRadius=0.45000000000000001
|
|
||||||
DeconvAmount=100
|
|
||||||
DeconvDamping=0
|
|
||||||
DeconvIterations=100
|
|
||||||
|
|
||||||
[Color Management]
|
|
||||||
InputProfile=(cameraICC)
|
|
||||||
ToneCurve=false
|
|
||||||
ApplyLookTable=true
|
|
||||||
ApplyBaselineExposureOffset=true
|
|
||||||
ApplyHueSatMap=true
|
|
||||||
DCPIlluminant=0
|
|
||||||
WorkingProfile=ProPhoto
|
|
||||||
WorkingTRC=none
|
|
||||||
Will=def
|
|
||||||
Wprim=def
|
|
||||||
WorkingTRCGamma=2.3999999999999999
|
|
||||||
WorkingTRCSlope=12.92
|
|
||||||
Redx=0.73470000000000002
|
|
||||||
Redy=0.26529999999999998
|
|
||||||
Grex=0.15959999999999999
|
|
||||||
Grey=0.84040000000000004
|
|
||||||
Blux=0.036600000000000001
|
|
||||||
Bluy=0.0001
|
|
||||||
LabGridcieALow=0.51763000000000003
|
|
||||||
LabGridcieBLow=-0.33582000000000001
|
|
||||||
LabGridcieAHigh=-0.75163000000000002
|
|
||||||
LabGridcieBHigh=-0.81799999999999995
|
|
||||||
LabGridcieGx=-0.69164000000000003
|
|
||||||
LabGridcieGy=-0.70909
|
|
||||||
LabGridcieWx=-0.18964
|
|
||||||
LabGridcieWy=-0.16636000000000001
|
|
||||||
Preser=0
|
|
||||||
Fbw=false
|
|
||||||
OutputProfile=RTv4_sRGB
|
|
||||||
aIntent=Relative
|
|
||||||
OutputProfileIntent=Relative
|
|
||||||
OutputBPC=true
|
|
||||||
|
|
||||||
[Wavelet]
|
|
||||||
Enabled=false
|
|
||||||
Strength=100
|
|
||||||
Balance=0
|
|
||||||
Sigmafin=1
|
|
||||||
Sigmaton=1
|
|
||||||
Sigmacol=1
|
|
||||||
Sigmadir=1
|
|
||||||
Rangeab=20
|
|
||||||
Protab=0
|
|
||||||
Iter=0
|
|
||||||
MaxLev=7
|
|
||||||
TilesMethod=full
|
|
||||||
complexMethod=normal
|
|
||||||
mixMethod=mix
|
|
||||||
sliMethod=sli
|
|
||||||
quaMethod=cons
|
|
||||||
DaubMethod=4_
|
|
||||||
ChoiceLevMethod=all
|
|
||||||
BackMethod=grey
|
|
||||||
LevMethod=4
|
|
||||||
DirMethod=all
|
|
||||||
CBgreenhigh=0
|
|
||||||
CBgreenmed=0
|
|
||||||
CBgreenlow=0
|
|
||||||
CBbluehigh=0
|
|
||||||
CBbluemed=0
|
|
||||||
CBbluelow=0
|
|
||||||
Ballum=7
|
|
||||||
Sigm=1
|
|
||||||
Levden=0
|
|
||||||
Thrden=0
|
|
||||||
Limden=0
|
|
||||||
Balchrom=0
|
|
||||||
Chromfine=0
|
|
||||||
Chromcoarse=0
|
|
||||||
MergeL=20
|
|
||||||
MergeC=20
|
|
||||||
Softrad=0
|
|
||||||
Softradend=0
|
|
||||||
Strend=50
|
|
||||||
Detend=0
|
|
||||||
Thrend=0
|
|
||||||
Expcontrast=false
|
|
||||||
Expchroma=false
|
|
||||||
Expedge=false
|
|
||||||
expbl=false
|
|
||||||
Expresid=false
|
|
||||||
Expfinal=false
|
|
||||||
Exptoning=false
|
|
||||||
Expnoise=false
|
|
||||||
Expclari=false
|
|
||||||
LabGridALow=0
|
|
||||||
LabGridBLow=0
|
|
||||||
LabGridAHigh=0
|
|
||||||
LabGridBHigh=0
|
|
||||||
Contrast1=0
|
|
||||||
Contrast2=0
|
|
||||||
Contrast3=0
|
|
||||||
Contrast4=0
|
|
||||||
Contrast5=0
|
|
||||||
Contrast6=0
|
|
||||||
Contrast7=0
|
|
||||||
Contrast8=0
|
|
||||||
Contrast9=0
|
|
||||||
Chroma1=0
|
|
||||||
Chroma2=0
|
|
||||||
Chroma3=0
|
|
||||||
Chroma4=0
|
|
||||||
Chroma5=0
|
|
||||||
Chroma6=0
|
|
||||||
Chroma7=0
|
|
||||||
Chroma8=0
|
|
||||||
Chroma9=0
|
|
||||||
ContExtra=0
|
|
||||||
HSMethod=with
|
|
||||||
HLRange=50;75;100;98;
|
|
||||||
SHRange=0;2;50;25;
|
|
||||||
Edgcont=0;10;75;40;
|
|
||||||
Level0noise=0;0;
|
|
||||||
Level1noise=0;0;
|
|
||||||
Level2noise=0;0;
|
|
||||||
Level3noise=0;0;
|
|
||||||
Leveldenoise=0;0;
|
|
||||||
Levelsigm=1;1;
|
|
||||||
ThresholdHighlight=4
|
|
||||||
ThresholdShadow=5
|
|
||||||
Edgedetect=90
|
|
||||||
Edgedetectthr=20
|
|
||||||
EdgedetectthrHi=0
|
|
||||||
Edgesensi=60
|
|
||||||
Edgeampli=10
|
|
||||||
ThresholdChroma=5
|
|
||||||
CHromaMethod=without
|
|
||||||
Medgreinf=less
|
|
||||||
Ushamethod=clari
|
|
||||||
CHSLromaMethod=SL
|
|
||||||
EDMethod=CU
|
|
||||||
NPMethod=none
|
|
||||||
BAMethod=none
|
|
||||||
TMMethod=cont
|
|
||||||
ChromaLink=0
|
|
||||||
ContrastCurve=1;0;0.25;0.34999999999999998;0.34999999999999998;0.5;0.75;0.34999999999999998;0.34999999999999998;0.90000000000000002;0;0.34999999999999998;0.34999999999999998;
|
|
||||||
blcurve=1;0;0;0;0.34999999999999998;0.5;0;0.34999999999999998;0.34999999999999998;1;0;0.34999999999999998;0.34999999999999998;
|
|
||||||
Pastlev=0;2;30;20;
|
|
||||||
Satlev=30;45;130;100;
|
|
||||||
OpacityCurveRG=1;0;0.5;0.34999999999999998;0.34999999999999998;1;0.5;0.34999999999999998;0.34999999999999998;
|
|
||||||
OpacityCurveBY=1;0;0.5;0.34999999999999998;0.34999999999999998;1;0.5;0.34999999999999998;0.34999999999999998;
|
|
||||||
wavdenoise=1;0;1;0.34999999999999998;0.34999999999999998;0.5;1;0.34999999999999998;0.34999999999999998;1;1;0.34999999999999998;0.34999999999999998;
|
|
||||||
wavdenoiseh=1;0;1;0.34999999999999998;0.34999999999999998;0.5;1;0.34999999999999998;0.34999999999999998;1;1;0.34999999999999998;0.34999999999999998;
|
|
||||||
OpacityCurveW=1;0;0.34999999999999998;0.34999999999999998;0;0.34999999999999998;0.75;0.34999999999999998;0.34999999999999998;0.59999999999999998;0.75;0.34999999999999998;0.34999999999999998;1;0.34999999999999998;0;0;
|
|
||||||
OpacityCurveWL=1;0;0.5;0.34999999999999998;0.34999999999999998;1;0.5;0.34999999999999998;0.34999999999999998;
|
|
||||||
HHcurve=0;
|
|
||||||
Wavguidcurve=0;
|
|
||||||
Wavhuecurve=0;
|
|
||||||
CHcurve=0;
|
|
||||||
WavclCurve=0;
|
|
||||||
Median=false
|
|
||||||
Medianlev=false
|
|
||||||
Linkedg=false
|
|
||||||
CBenab=false
|
|
||||||
Lipst=false
|
|
||||||
Skinprotect=0
|
|
||||||
chrwav=0
|
|
||||||
bluwav=1
|
|
||||||
Hueskin=-5;25;170;120;
|
|
||||||
Edgrad=15
|
|
||||||
Edgeffect=1
|
|
||||||
Edgval=0
|
|
||||||
ThrEdg=10
|
|
||||||
AvoidColorShift=false
|
|
||||||
Showmask=false
|
|
||||||
Oldsh=true
|
|
||||||
TMr=false
|
|
||||||
Sigma=1
|
|
||||||
Offset=1
|
|
||||||
Lowthr=40
|
|
||||||
ResidualcontShadow=0
|
|
||||||
ResidualcontHighlight=0
|
|
||||||
ThresholdResidShadow=30
|
|
||||||
ThresholdResidHighLight=70
|
|
||||||
Residualradius=40
|
|
||||||
Residualchroma=0
|
|
||||||
Residualblur=0
|
|
||||||
Residualblurc=0
|
|
||||||
ResidualTM=0
|
|
||||||
ResidualEDGS=1.3999999999999999
|
|
||||||
ResidualSCALE=1
|
|
||||||
Residualgamma=1
|
|
||||||
HueRangeResidual=0
|
|
||||||
HueRange=-260;-250;-130;-140;
|
|
||||||
Contrast=0
|
|
||||||
|
|
||||||
[Spot removal]
|
|
||||||
Enabled=false
|
|
||||||
|
|
||||||
[Directional Pyramid Equalizer]
|
|
||||||
Enabled=false
|
|
||||||
Gamutlab=false
|
|
||||||
cbdlMethod=bef
|
|
||||||
Mult0=1
|
|
||||||
Mult1=1
|
|
||||||
Mult2=1
|
|
||||||
Mult3=1
|
|
||||||
Mult4=1
|
|
||||||
Mult5=1
|
|
||||||
Threshold=0.20000000000000001
|
|
||||||
Skinprotect=0
|
|
||||||
Hueskin=-5;25;170;120;
|
|
||||||
|
|
||||||
[HSV Equalizer]
|
|
||||||
Enabled=false
|
|
||||||
HCurve=0;
|
|
||||||
SCurve=0;
|
|
||||||
VCurve=0;
|
|
||||||
|
|
||||||
[SoftLight]
|
|
||||||
Enabled=false
|
|
||||||
Strength=30
|
|
||||||
|
|
||||||
[Film Simulation]
|
|
||||||
Enabled=false
|
|
||||||
ClutFilename=
|
|
||||||
Strength=100
|
|
||||||
|
|
||||||
[RGB Curves]
|
|
||||||
Enabled=false
|
|
||||||
LumaMode=false
|
|
||||||
rCurve=0;
|
|
||||||
gCurve=0;
|
|
||||||
bCurve=0;
|
|
||||||
|
|
||||||
[ColorToning]
|
|
||||||
Enabled=false
|
|
||||||
Method=LabRegions
|
|
||||||
Lumamode=true
|
|
||||||
Twocolor=Std
|
|
||||||
Redlow=0
|
|
||||||
Greenlow=0
|
|
||||||
Bluelow=0
|
|
||||||
Satlow=0
|
|
||||||
Balance=0
|
|
||||||
Sathigh=0
|
|
||||||
Redmed=0
|
|
||||||
Greenmed=0
|
|
||||||
Bluemed=0
|
|
||||||
Redhigh=0
|
|
||||||
Greenhigh=0
|
|
||||||
Bluehigh=0
|
|
||||||
Autosat=true
|
|
||||||
OpacityCurve=1;0;0.29999999999999999;0.34999999999999998;0;0.25;0.80000000000000004;0.34999999999999998;0.34999999999999998;0.69999999999999996;0.80000000000000004;0.34999999999999998;0.34999999999999998;1;0.29999999999999999;0;0;
|
|
||||||
ColorCurve=1;0.050000000000000003;0.62;0.25;0.25;0.58499999999999996;0.11;0.25;0.25;
|
|
||||||
SatProtectionThreshold=30
|
|
||||||
SaturatedOpacity=80
|
|
||||||
Strength=50
|
|
||||||
HighlightsColorSaturation=60;80;
|
|
||||||
ShadowsColorSaturation=80;208;
|
|
||||||
ClCurve=3;0;0;0.34999999999999998;0.65000000000000002;1;1;
|
|
||||||
Cl2Curve=3;0;0;0.34999999999999998;0.65000000000000002;1;1;
|
|
||||||
LabGridALow=0
|
|
||||||
LabGridBLow=0
|
|
||||||
LabGridAHigh=0
|
|
||||||
LabGridBHigh=0
|
|
||||||
LabRegionA_1=0
|
|
||||||
LabRegionB_1=0
|
|
||||||
LabRegionSaturation_1=0
|
|
||||||
LabRegionSlope_1=1
|
|
||||||
LabRegionOffset_1=0
|
|
||||||
LabRegionPower_1=1
|
|
||||||
LabRegionHueMask_1=1;0.16666666699999999;1;0.34999999999999998;0.34999999999999998;0.82877752459999998;1;0.34999999999999998;0.34999999999999998;
|
|
||||||
LabRegionChromaticityMask_1=1;0;1;0.34999999999999998;0.34999999999999998;1;1;0.34999999999999998;0.34999999999999998;
|
|
||||||
LabRegionLightnessMask_1=1;0;1;0.34999999999999998;0.34999999999999998;1;1;0.34999999999999998;0.34999999999999998;
|
|
||||||
LabRegionMaskBlur_1=0
|
|
||||||
LabRegionChannel_1=-1
|
|
||||||
LabRegionsShowMask=-1
|
|
||||||
|
|
||||||
[RAW]
|
|
||||||
DarkFrame=
|
|
||||||
DarkFrameAuto=false
|
|
||||||
FlatFieldFile=
|
|
||||||
FlatFieldAutoSelect=false
|
|
||||||
FlatFieldBlurRadius=32
|
|
||||||
FlatFieldBlurType=Area Flatfield
|
|
||||||
FlatFieldAutoClipControl=false
|
|
||||||
FlatFieldClipControl=0
|
|
||||||
CA=true
|
|
||||||
CAAvoidColourshift=true
|
|
||||||
CAAutoIterations=2
|
|
||||||
CARed=0
|
|
||||||
CABlue=0
|
|
||||||
HotPixelFilter=false
|
|
||||||
DeadPixelFilter=false
|
|
||||||
HotDeadPixelThresh=100
|
|
||||||
PreExposure=1
|
|
||||||
|
|
||||||
[RAW Bayer]
|
|
||||||
Method=amaze
|
|
||||||
Border=4
|
|
||||||
ImageNum=1
|
|
||||||
CcSteps=0
|
|
||||||
PreBlack0=0
|
|
||||||
PreBlack1=0
|
|
||||||
PreBlack2=0
|
|
||||||
PreBlack3=0
|
|
||||||
PreTwoGreen=true
|
|
||||||
LineDenoise=0
|
|
||||||
LineDenoiseDirection=3
|
|
||||||
GreenEqThreshold=0
|
|
||||||
DCBIterations=2
|
|
||||||
DCBEnhance=true
|
|
||||||
LMMSEIterations=2
|
|
||||||
DualDemosaicAutoContrast=true
|
|
||||||
DualDemosaicContrast=20
|
|
||||||
PixelShiftMotionCorrectionMethod=1
|
|
||||||
PixelShiftEperIso=0
|
|
||||||
PixelShiftSigma=1
|
|
||||||
PixelShiftShowMotion=false
|
|
||||||
PixelShiftShowMotionMaskOnly=false
|
|
||||||
pixelShiftHoleFill=true
|
|
||||||
pixelShiftAverage=false
|
|
||||||
pixelShiftMedian=false
|
|
||||||
pixelShiftGreen=true
|
|
||||||
pixelShiftBlur=true
|
|
||||||
pixelShiftSmoothFactor=0.69999999999999996
|
|
||||||
pixelShiftEqualBright=false
|
|
||||||
pixelShiftEqualBrightChannel=false
|
|
||||||
pixelShiftNonGreenCross=true
|
|
||||||
pixelShiftDemosaicMethod=amaze
|
|
||||||
PDAFLinesFilter=false
|
|
||||||
|
|
||||||
[RAW X-Trans]
|
|
||||||
Method=3-pass (best)
|
|
||||||
DualDemosaicAutoContrast=true
|
|
||||||
DualDemosaicContrast=20
|
|
||||||
Border=7
|
|
||||||
CcSteps=0
|
|
||||||
PreBlackRed=0
|
|
||||||
PreBlackGreen=0
|
|
||||||
PreBlackBlue=0
|
|
||||||
|
|
||||||
[MetaData]
|
|
||||||
Mode=0
|
|
||||||
|
|
||||||
[Film Negative]
|
|
||||||
Enabled=false
|
|
||||||
RedRatio=1.3600000000000001
|
|
||||||
GreenExponent=1.5
|
|
||||||
BlueRatio=0.85999999999999999
|
|
||||||
ColorSpace=1
|
|
||||||
RefInput=0;0;0;
|
|
||||||
RefOutput=0;0;0;
|
|
||||||
|
|
||||||
[RAW Preprocess WB]
|
|
||||||
Mode=1
|
|
@ -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>
|
|
10
requirements.txt
Normal file
10
requirements.txt
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
exif==1.6.1
|
||||||
|
imageio==2.37.0
|
||||||
|
Jinja2==3.1.6
|
||||||
|
Markdown==3.8
|
||||||
|
MarkupSafe==3.0.2
|
||||||
|
numpy==2.2.3
|
||||||
|
pillow==11.1.0
|
||||||
|
plum-py==0.8.7
|
||||||
|
progress==1.6
|
||||||
|
rawpy==0.24.0
|
BIN
screenshots/album.png
Normal file
BIN
screenshots/album.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 712 KiB |
BIN
screenshots/page.png
Normal file
BIN
screenshots/page.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 MiB |
32
src/bulk_album.py
Normal file
32
src/bulk_album.py
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from picture import Picture
|
||||||
|
|
||||||
|
from path import Path
|
||||||
|
|
||||||
|
env = Environment(loader=FileSystemLoader('src/templates'))
|
||||||
|
album_template = env.get_template('bulk_album.jinja')
|
||||||
|
|
||||||
|
class BulkAlbum():
|
||||||
|
|
||||||
|
def __init__(self, name: str, albums_path: Path, pictures: list[Picture] = None, is_repertoried: bool = False):
|
||||||
|
self.name: str = name
|
||||||
|
self._pictures: list[Picture] = pictures or []
|
||||||
|
self._is_repertoried: bool = is_repertoried
|
||||||
|
self.path: Path = Path(albums_path, f"{name}.html")
|
||||||
|
|
||||||
|
def add_picture(self, picture: Picture) -> None:
|
||||||
|
self._pictures.append(picture)
|
||||||
|
|
||||||
|
def _to_html(self) -> str|None:
|
||||||
|
html_rendered = album_template.render(album=self)
|
||||||
|
return html_rendered
|
||||||
|
|
||||||
|
def create(self) -> Path:
|
||||||
|
with open(self.path.get_absolute_path(), "w") as f:
|
||||||
|
f.write(self._to_html())
|
78
src/bulk_page.py
Normal file
78
src/bulk_page.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
import markdown
|
||||||
|
import os
|
||||||
|
|
||||||
|
from path import Path
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from bulk_page import Page
|
||||||
|
from picture import Picture
|
||||||
|
|
||||||
|
env = Environment(loader=FileSystemLoader('src/templates'))
|
||||||
|
page_template = env.get_template('bulk_page.jinja')
|
||||||
|
|
||||||
|
class BulkPage():
|
||||||
|
|
||||||
|
def __init__(self, path: Path, name: str, pictures: list[Picture] = None, prev: Page|None = None, next: Page|None = None):
|
||||||
|
self.name: str = name
|
||||||
|
self._path: Path = path
|
||||||
|
self._pictures: list[Picture] = pictures or []
|
||||||
|
self._exif: Path = Path(self._path, "exif.txt")
|
||||||
|
self._readme: Path = Path(self._path, "readme.md")
|
||||||
|
self._raw: Path = Path(self._path, name + ".NEF")
|
||||||
|
self.html: Path = Path(self._path, "page.html")
|
||||||
|
self.prev: Page = prev
|
||||||
|
self.next: Page = next
|
||||||
|
if (not self._readme.exist()):
|
||||||
|
self._readme.touch()
|
||||||
|
|
||||||
|
def add_picture(self, picture: Picture) -> None:
|
||||||
|
self._pictures.append(picture)
|
||||||
|
|
||||||
|
def get_pictures(self) -> list[Picture]:
|
||||||
|
return self._pictures
|
||||||
|
|
||||||
|
def _to_html(self) -> str|None:
|
||||||
|
html_rendered = page_template.render(page=self)
|
||||||
|
return html_rendered
|
||||||
|
|
||||||
|
def create(self) -> Path:
|
||||||
|
with open(self.html.get_absolute_path(), "w") as f:
|
||||||
|
f.write(self._to_html())
|
||||||
|
|
||||||
|
def render_readme(self) -> str|None:
|
||||||
|
if not self._readme.exist():
|
||||||
|
return None
|
||||||
|
with open(self._readme.get_absolute_path(), 'r') as f:
|
||||||
|
text = f.read()
|
||||||
|
if len(text) == 0:
|
||||||
|
return None
|
||||||
|
html = markdown.markdown(text)
|
||||||
|
return html
|
||||||
|
|
||||||
|
def _gen_exif(self):
|
||||||
|
if self._raw.exist():
|
||||||
|
if os.system(f"exiftool {self._raw.get_absolute_path()} > {self._exif.get_absolute_path()} 2>/dev/null") == 0:
|
||||||
|
return 0
|
||||||
|
os.remove(self._exif.get_absolute_path())
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def get_exif(self) -> Path | None:
|
||||||
|
if not self._exif.exist():
|
||||||
|
if (self._gen_exif()):
|
||||||
|
return None
|
||||||
|
return self._exif
|
||||||
|
|
||||||
|
def render_exif(self):
|
||||||
|
if not self.get_exif():
|
||||||
|
return None
|
||||||
|
|
||||||
|
with open(self._exif.get_absolute_path()) as f:
|
||||||
|
return f.read()
|
||||||
|
|
||||||
|
def get_raw(self):
|
||||||
|
return self._raw
|
4
src/config.py
Normal file
4
src/config.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
|
||||||
|
|
||||||
|
CREATE_GENERAL_ALBUM: bool = True
|
||||||
|
THUMB_DIMENSION: tuple[int, int] = (200, 200)
|
@ -1,4 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
def display(executable: str):
|
|
||||||
print(f"{executable} {{Path of your pictures}} {{Path of the site}}")
|
|
135
src/main.py
135
src/main.py
@ -1,14 +1,131 @@
|
|||||||
import sys
|
import sys
|
||||||
import help
|
import os
|
||||||
import PIL
|
from progress.bar import Bar
|
||||||
|
|
||||||
|
from path import Path
|
||||||
|
from picture import Picture
|
||||||
|
from bulk_page import BulkPage
|
||||||
|
from bulk_album import BulkAlbum
|
||||||
|
import argparse
|
||||||
|
import config
|
||||||
|
|
||||||
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
env = Environment(loader=FileSystemLoader('src/templates'))
|
||||||
|
home_template = env.get_template('home.jinja')
|
||||||
|
|
||||||
|
def argument_parsing():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("site_path", help="the folder of your site MUST BE ALWAYS BEFORT PARAMETERS", type=str)
|
||||||
|
parser.add_argument("-r", '--regen', help="Regenerate (t)thumb (s)small", type=str)
|
||||||
|
args = parser.parse_args()
|
||||||
|
return args
|
||||||
|
|
||||||
|
def scan_pages(folders: list[Path]) -> list[BulkPage]:
|
||||||
|
pages: list[BulkPage] = []
|
||||||
|
prev: BulkPage = None
|
||||||
|
with Bar("Scanning Pages...", max=len(folders)) as bar:
|
||||||
|
for folder in folders:
|
||||||
|
files: list[Path] = folder.get_files()
|
||||||
|
|
||||||
|
page: BulkPage = BulkPage(folder, folder.get_name(), prev=prev)
|
||||||
|
|
||||||
|
raw: Path = Path(folder, folder.get_name() + ".NEF")
|
||||||
|
id: int = 0
|
||||||
|
for file in files:
|
||||||
|
if file.get_name().endswith(".png"):
|
||||||
|
page.add_picture(Picture(file, id, page=page, raw=raw))
|
||||||
|
id += 1
|
||||||
|
|
||||||
|
if len(page.get_pictures()) == 0:
|
||||||
|
bar.next()
|
||||||
|
continue
|
||||||
|
|
||||||
|
pages.append(page)
|
||||||
|
if prev is not None:
|
||||||
|
prev.next = page
|
||||||
|
prev = page
|
||||||
|
|
||||||
|
bar.next()
|
||||||
|
pages[-1].next = pages[0]
|
||||||
|
pages[0].prev = pages[-1]
|
||||||
|
return pages
|
||||||
|
|
||||||
|
def create_pages(pages: list[BulkPage]) -> None:
|
||||||
|
with Bar("Generating Pages...", max=len(pages)) as bar:
|
||||||
|
for page in pages:
|
||||||
|
page.create()
|
||||||
|
bar.next()
|
||||||
|
|
||||||
|
def scan_albums(pages: list[BulkPage], albums_path: Path) -> list[BulkAlbum]:
|
||||||
|
albums: dict[str, BulkAlbum] = {}
|
||||||
|
with Bar("Scanning pages...", max=len(pages)) as bar:
|
||||||
|
for page in pages:
|
||||||
|
for picture in page.get_pictures():
|
||||||
|
for album_name in picture.get_albums_name():
|
||||||
|
album: BulkAlbum | None = albums.get(album_name)
|
||||||
|
if (album is None):
|
||||||
|
album = BulkAlbum(album_name, albums_path)
|
||||||
|
albums.update({album_name: album})
|
||||||
|
picture.albums.append(album)
|
||||||
|
album.add_picture(picture)
|
||||||
|
bar.next()
|
||||||
|
return (albums.values())
|
||||||
|
|
||||||
|
def create_albums(albums: list[BulkAlbum]) -> None:
|
||||||
|
with Bar("Generating albums...", max=len(albums)) as bar:
|
||||||
|
for album in albums:
|
||||||
|
album.create()
|
||||||
|
bar.next()
|
||||||
|
|
||||||
|
def gen_bulk(bulk_path: Path):
|
||||||
|
album_path: Path = Path(bulk_path, "albums")
|
||||||
|
|
||||||
|
pages: list[BulkPage] = scan_pages(bulk_path.get_dirs())
|
||||||
|
albums: list[BulkAlbum] = scan_albums(pages, album_path)
|
||||||
|
|
||||||
|
if config.CREATE_GENERAL_ALBUM:
|
||||||
|
for album in albums:
|
||||||
|
if (album.name == "general"):
|
||||||
|
album.path = Path(bulk_path, "index.html")
|
||||||
|
|
||||||
|
Path("./src/templates/bulk_page.css").copy_to(Path(bulk_path, "bulk_page.css"))
|
||||||
|
create_pages(pages)
|
||||||
|
|
||||||
|
Path("./src/templates/bulk_album.css").copy_to(Path(bulk_path, "bulk_album.css"))
|
||||||
|
if (not album_path.exist()):
|
||||||
|
album_path.create()
|
||||||
|
create_albums(albums)
|
||||||
|
|
||||||
|
|
||||||
|
def regen(bulk_path: Path, is_thumb: bool, is_small: bool):
|
||||||
|
pages: list[BulkPage] = scan_pages(bulk_path.get_dirs())
|
||||||
|
with Bar("Regenerating assets...", max=len(pages)) as bar:
|
||||||
|
for page in pages:
|
||||||
|
for picture in page.get_pictures():
|
||||||
|
if is_thumb:
|
||||||
|
picture.gen_thumb()
|
||||||
|
if is_small:
|
||||||
|
picture.gen_small()
|
||||||
|
bar.next()
|
||||||
|
|
||||||
|
def gen_home(site_path: Path) -> None:
|
||||||
|
home_path = Path(site_path, "index.html")
|
||||||
|
|
||||||
|
with open(home_path.get_absolute_path(), "w") as f:
|
||||||
|
f.write(home_template.render())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
args = argument_parsing()
|
||||||
|
site_path: Path = Path(args.site_path)
|
||||||
|
bulk_path: Path = Path(site_path, "bulk/")
|
||||||
|
if args.regen is not None:
|
||||||
|
regen(bulk_path, 't' in args.regen, 's' in args.regen)
|
||||||
|
gen_bulk(bulk_path)
|
||||||
|
gen_home(site_path)
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
|
||||||
help.display(sys.argv[0])
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (__name__ == "__main__"):
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
74
src/path.py
Normal file
74
src/path.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import shutil
|
||||||
|
class Path():
|
||||||
|
|
||||||
|
def __init__(self, *paths: str | Path):
|
||||||
|
self._absolute_path: str = ""
|
||||||
|
for path in paths:
|
||||||
|
self._absolute_path = os.path.join(self._absolute_path, path._absolute_path if isinstance(path, Path) else path)
|
||||||
|
self._absolute_path = os.path.abspath(self._absolute_path)
|
||||||
|
self._name: str = os.path.basename(self._absolute_path)
|
||||||
|
self._dirpath: str = os.path.dirname(self._absolute_path)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def get_dirpath(self):
|
||||||
|
return self._dirpath
|
||||||
|
|
||||||
|
def get_url(self):
|
||||||
|
site_path: Path = Path(sys.argv[1])
|
||||||
|
return self._absolute_path[len(site_path._absolute_path):]
|
||||||
|
|
||||||
|
def get_absolute_path(self):
|
||||||
|
return self._absolute_path
|
||||||
|
|
||||||
|
def get_name(self):
|
||||||
|
if not self.exist():
|
||||||
|
return None
|
||||||
|
return self._name
|
||||||
|
|
||||||
|
def touch(self) -> None:
|
||||||
|
if (self.exist()):
|
||||||
|
return None
|
||||||
|
open(self.get_absolute_path(), "w+").close()
|
||||||
|
|
||||||
|
def create(self) -> None:
|
||||||
|
os.makedirs(self.get_absolute_path())
|
||||||
|
|
||||||
|
def exist(self) -> bool:
|
||||||
|
return os.path.exists(self.get_absolute_path())
|
||||||
|
|
||||||
|
def get_dirs(self) -> list[Path]:
|
||||||
|
dirs: list[Path] = []
|
||||||
|
elements = os.listdir(self.get_absolute_path())
|
||||||
|
elements.sort()
|
||||||
|
elements.reverse()
|
||||||
|
for element in elements:
|
||||||
|
path: Path = Path(self._absolute_path, element)
|
||||||
|
if (os.path.isdir(path.get_absolute_path())):
|
||||||
|
dirs.append(path)
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
def get_files(self) -> list[Path]:
|
||||||
|
files: list[Path] = []
|
||||||
|
elements = os.listdir(self.get_absolute_path())
|
||||||
|
elements.sort()
|
||||||
|
elements.reverse()
|
||||||
|
for element in elements:
|
||||||
|
path: Path = Path(self._absolute_path, element)
|
||||||
|
if (os.path.isfile(path.get_absolute_path())):
|
||||||
|
files.append(path)
|
||||||
|
return files
|
||||||
|
|
||||||
|
def copy_to(self, destination: Path) -> None:
|
||||||
|
shutil.copy2(self.get_absolute_path(), destination.get_absolute_path())
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self._absolute_path
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f"Path({self._absolute_path})"
|
72
src/picture.py
Normal file
72
src/picture.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
import os
|
||||||
|
|
||||||
|
from path import Path
|
||||||
|
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
import config
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from bulk_page import BulkPage
|
||||||
|
from bulk_album import Album
|
||||||
|
|
||||||
|
class Picture():
|
||||||
|
def __init__(self, picture_path: Path, id: int, page: BulkPage = None, raw: Path|None = None, is_repertoried: bool = True):
|
||||||
|
self._large: Path = picture_path
|
||||||
|
self._small: Path = Path(picture_path.get_absolute_path()[:-4] + "_small.jpg")
|
||||||
|
self._thumb: Path = Path(picture_path.get_absolute_path()[:-4] + "_thumb.jpg")
|
||||||
|
self._profile_file: Path = Path(picture_path.get_absolute_path() + ".out.pp3")
|
||||||
|
self._albums_file: Path = Path(picture_path.get_absolute_path()[:-4] + "_albums.txt")
|
||||||
|
self._raw: Path|None = raw
|
||||||
|
self.id: int = id
|
||||||
|
self._page: BulkPage = page
|
||||||
|
self._albums_name: list[str] = []
|
||||||
|
self.albums: list[Album] = []
|
||||||
|
if self._albums_file.exist():
|
||||||
|
with open(self._albums_file.get_absolute_path(), "r+") as f:
|
||||||
|
albums_name: list[str] = f.read()
|
||||||
|
if (len(albums_name)):
|
||||||
|
self._albums_name += albums_name.split("\n")
|
||||||
|
else:
|
||||||
|
self._albums_file.touch()
|
||||||
|
if (config.CREATE_GENERAL_ALBUM):
|
||||||
|
self._albums_name.append("general")
|
||||||
|
self._is_reperoried: bool = is_repertoried
|
||||||
|
self.get_small()
|
||||||
|
self.get_thumb()
|
||||||
|
|
||||||
|
def get_page(self):
|
||||||
|
return self._page
|
||||||
|
|
||||||
|
def get_albums_name(self):
|
||||||
|
return self._albums_name
|
||||||
|
|
||||||
|
def get_small(self):
|
||||||
|
if not self._small.exist():
|
||||||
|
self.gen_small()
|
||||||
|
return self._small
|
||||||
|
|
||||||
|
def get_thumb(self):
|
||||||
|
if not self._thumb.exist():
|
||||||
|
self.gen_thumb()
|
||||||
|
return self._thumb
|
||||||
|
|
||||||
|
def get_large(self):
|
||||||
|
return self._large
|
||||||
|
|
||||||
|
def get_profile_file(self):
|
||||||
|
return self._profile_file
|
||||||
|
|
||||||
|
def gen_thumb(self):
|
||||||
|
im = Image.open(self._large.get_absolute_path())
|
||||||
|
im.thumbnail(config.THUMB_DIMENSION)
|
||||||
|
im.save(self._thumb.get_absolute_path(), "JPEG")
|
||||||
|
|
||||||
|
def gen_small(self):
|
||||||
|
im = Image.open(self._large.get_absolute_path()).convert("RGB")
|
||||||
|
im.save(self._small.get_absolute_path(), quality=95, optimize=True)
|
||||||
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<img src="./img1.je">
|
|
||||||
</body>
|
|
||||||
</html>
|
|
43
src/templates/bulk_album.css
Normal file
43
src/templates/bulk_album.css
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
:root {
|
||||||
|
--bg1: #002b36;
|
||||||
|
--bg2: #073642;
|
||||||
|
--content1: #586e75;
|
||||||
|
--content2: #657b83;
|
||||||
|
--content3: #839496;
|
||||||
|
--content4: #93a1a1;
|
||||||
|
--lbg1: #eee8d5;
|
||||||
|
--lbg2: #fdf6e3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picture-container {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-around;
|
||||||
|
background-color: var(--bg2);
|
||||||
|
width: auto;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-direction: column;
|
||||||
|
background-color: var(--bg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: contain
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: var(--content1);
|
||||||
|
padding: 10px;
|
||||||
|
margin: 10px;
|
||||||
|
height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
19
src/templates/bulk_album.jinja
Normal file
19
src/templates/bulk_album.jinja
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bulk/bulk_album.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1>{{ album.name }}</h1>
|
||||||
|
<div class="picture-container">
|
||||||
|
{% for picture in album._pictures %}
|
||||||
|
<a href="{{ picture.get_page().html.get_url() }}#{{ picture.id }}">
|
||||||
|
<img src="{{ picture.get_thumb().get_url() }}">
|
||||||
|
</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
87
src/templates/bulk_page.css
Normal file
87
src/templates/bulk_page.css
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
:root {
|
||||||
|
--bg1: #002b36;
|
||||||
|
--bg2: #073642;
|
||||||
|
--content1: #586e75;
|
||||||
|
--content2: #657b83;
|
||||||
|
--content3: #839496;
|
||||||
|
--content4: #93a1a1;
|
||||||
|
--lbg1: #eee8d5;
|
||||||
|
--lbg2: #fdf6e3;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: var(--bg1);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin: 15% 15%;
|
||||||
|
margin-top: 5%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.readme {
|
||||||
|
background-color: var(--bg2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picture-container {
|
||||||
|
background-color: var(--bg2);
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picture {
|
||||||
|
padding: 5px;
|
||||||
|
background-color: var(--content1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.albums_container {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.meta-picture, .navigation {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width:767px) {
|
||||||
|
body {
|
||||||
|
margin: 0% 0%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.exif, .readme {
|
||||||
|
width: 100%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.download {
|
||||||
|
width: 100%;
|
||||||
|
background-color: var(--bg2);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exif summary {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.exif details {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
background-color: var(--bg2);
|
||||||
|
}
|
70
src/templates/bulk_page.jinja
Normal file
70
src/templates/bulk_page.jinja
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="/bulk/bulk_page.css">
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class="navigation">
|
||||||
|
{% if page.prev %}
|
||||||
|
<a href="{{ page.prev.html.get_url() }}">Prev</a>
|
||||||
|
{% endif %}
|
||||||
|
{% if page.next %}
|
||||||
|
<a class="next" href="{{ page.next.html.get_url() }}">Next</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% if page.render_readme() %}
|
||||||
|
<div class="readme">
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
README
|
||||||
|
</summary>
|
||||||
|
<div class="readme-content">
|
||||||
|
{{page.render_readme()}}
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="picture-container">
|
||||||
|
{% for picture in page._pictures %}
|
||||||
|
<div class="picture-container-item" id="{{ picture.id}}">
|
||||||
|
<div class="picture">
|
||||||
|
<a href="{{ picture.get_small().get_url() }}">
|
||||||
|
<img src='{{ picture.get_small().get_url() }}'>
|
||||||
|
</a>
|
||||||
|
<div class="meta-picture">
|
||||||
|
<a href="{{ picture.get_large().get_url() }}">Large</a>
|
||||||
|
{% if picture._profile_file.exist() %}
|
||||||
|
<a class="profile" href="{{ picture.get_profile_file().get_url() }}">Raw therapee profile</a>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="albums_container">
|
||||||
|
<h1>Albums:</h1>
|
||||||
|
{% for album in picture.albums %}
|
||||||
|
<a href="{{ album.path.get_url() }}" class="album_item">{{ al }}</a>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% if page.get_raw().exist() %}
|
||||||
|
<div class="download">
|
||||||
|
<h1>Download</h1>
|
||||||
|
<a href="{{ page.get_raw().get_url() }}">RAW</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% if page.get_exif() %}
|
||||||
|
<div class="exif">
|
||||||
|
<details>
|
||||||
|
<summary>Exif</summary>
|
||||||
|
<pre>
|
||||||
|
{{ page.render_exif() }}
|
||||||
|
</pre>
|
||||||
|
</details>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
7
src/templates/home.jinja
Normal file
7
src/templates/home.jinja
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<a href="/bulk/"><h1>Site WIP go to BULK</h1></a>
|
||||||
|
</body>
|
||||||
|
</html>
|
57
tools/copy.py
Normal file
57
tools/copy.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import uuid
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import argparse
|
||||||
|
import hashlib
|
||||||
|
import shutil
|
||||||
|
from progress.bar import Bar
|
||||||
|
|
||||||
|
def argument_parsing():
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("input_folder", help="the folder of your raws", type=str)
|
||||||
|
parser.add_argument("output_folder", help="the location of your website", type=str)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
return args.input_folder, args.output_folder
|
||||||
|
|
||||||
|
def get_copy_info(path: str):
|
||||||
|
copy_info: dict[str, dict[str, str]] = {}
|
||||||
|
if os.path.exists(path):
|
||||||
|
with open(path, "r") as f:
|
||||||
|
for line in f.read().splitlines():
|
||||||
|
hash, og_name, new_name = line.split(" | ")
|
||||||
|
copy_info.update({hash: {"og_name": og_name, "new_name": new_name}})
|
||||||
|
return copy_info
|
||||||
|
|
||||||
|
def save_copy_info(path: str, copy_info: dict[str, dict[str, str]]):
|
||||||
|
copy_info_str: str = "\n".join([f"{hash} | {copy_info[hash]['og_name']} | {copy_info[hash]['new_name']}" for hash in copy_info.keys()])
|
||||||
|
with open(path, "w") as f:
|
||||||
|
f.write(copy_info_str)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
input_folder, output_folder = argument_parsing()
|
||||||
|
copy_path = os.path.join(output_folder, "ph_copy.txt")
|
||||||
|
copy_info: dict[str, str] = get_copy_info(copy_path)
|
||||||
|
files: list[str] = [os.path.join(input_folder, f) for f in os.listdir(input_folder)]
|
||||||
|
files = [f for f in files if os.path.isfile(f) and f.endswith(".NEF")]
|
||||||
|
files.sort()
|
||||||
|
with Bar("copying...", max=len(files)) as bar:
|
||||||
|
for file in files:
|
||||||
|
with open(file, 'rb') as f:
|
||||||
|
image_data = f.read()
|
||||||
|
file_extention: str = file.split(".")[-1]
|
||||||
|
hash: str = hashlib.sha256(image_data).hexdigest()
|
||||||
|
|
||||||
|
if copy_info.get(hash) is None:
|
||||||
|
new_name: str = f"{len(copy_info):05d}"
|
||||||
|
path: str = os.path.join(output_folder, new_name)
|
||||||
|
|
||||||
|
os.makedirs(path)
|
||||||
|
shutil.copy2(file, os.path.join(path, new_name + "." + file_extention))
|
||||||
|
|
||||||
|
copy_info.update({hash: {"og_name": os.path.basename(file), "new_name": new_name}})
|
||||||
|
bar.next()
|
||||||
|
save_copy_info(copy_path, copy_info)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
exit(main())
|
17
tools/rename.py
Normal file
17
tools/rename.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
from progress.bar import Bar
|
||||||
|
|
||||||
|
def main():
|
||||||
|
folders: list[str] = os.listdir(sys.argv[1])
|
||||||
|
with Bar("copying...", max=len(folders)) as bar:
|
||||||
|
for folder in folders:
|
||||||
|
if (len(folder) != 5):
|
||||||
|
if (folder.isdigit()):
|
||||||
|
new_name: str = f"{int(folder):05d}"
|
||||||
|
shutil.move(os.path.join(sys.argv[1], folder), os.path.join(sys.argv[1], new_name))
|
||||||
|
bar.next()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
exit(main())
|
Reference in New Issue
Block a user