summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/pyggle223
-rw-r--r--share/html_start15
2 files changed, 168 insertions, 70 deletions
diff --git a/bin/pyggle b/bin/pyggle
index f9b3d55..6e01589 100755
--- a/bin/pyggle
+++ b/bin/pyggle
@@ -38,6 +38,35 @@ def rotate_image(image, exif_tag):
return image
+def rotate_preview(filename, exif_tag):
+ if "Image Orientation" not in exif_tag:
+ return
+
+ orientation = exif_tag["Image Orientation"].values
+ rotation = None
+
+ if 3 in orientation:
+ rotation = "-1"
+ if 6 in orientation:
+ rotation = "-9"
+ if 8 in orientation:
+ rotation = "-2"
+
+ if not rotation:
+ return
+
+ subprocess.run(
+ [
+ "exiftran",
+ "-i",
+ rotation,
+ filename,
+ ],
+ stdout=subprocess.DEVNULL,
+ stderr=subprocess.DEVNULL,
+ )
+
+
def format_f(value, precision=1):
if value % 1 == 0:
return f"{value:.0f}"
@@ -257,6 +286,7 @@ class Thumbnail:
with_gps=False,
group_key_template=None,
file_key_template=None,
+ have_thumbnail=dict(),
):
self.filename = filename
self.jpegname = None
@@ -285,45 +315,65 @@ class Thumbnail:
except FileNotFoundError:
pass
- thumb_filename = filename.replace("/", "-")
- self.thumbname = f".thumbnails/{thumb_filename}"
- if not self.thumbname.lower().endswith((".jpeg", ".jpg")):
- self.thumbname += ".jpg"
-
- im = rotate_image(im, self.exif_tag)
- im.thumbnail((self.size * 4, self.size * 2))
- im = im.convert("RGB")
- im.save(self.thumbname, "JPEG")
-
- if filename.lower().endswith((".cr2", ".cr3", ".rw2")):
- try:
- jpegname = f".thumbnails/{thumb_filename}.p.jpg"
- subprocess.run(
- [
- "exiftool",
- "-quiet",
- "-binary",
- "-tagOut!",
- jpegname,
- "-PreviewImage",
- filename,
- ]
- )
- # JpgFromRaw tends to have higher resolution, so overwrite PreviewImage if it is present
- subprocess.run(
- [
- "exiftool",
- "-quiet",
- "-binary",
- "-tagOut!",
- jpegname,
- "-JpgFromRaw",
- filename,
- ]
- )
- self.jpegname = jpegname
- except FileNotFoundError:
- pass
+ have_subthumb = False
+
+ if "/" in filename:
+ sub_dirname, sub_filename = filename.rsplit("/", 1)
+ sub_thumbname = sub_filename
+ if not sub_thumbname.lower().endswith((".jpeg", ".jpg")):
+ sub_thumbname += ".jpg"
+ if os.path.exists(f"{sub_dirname}/.thumbnails/{sub_thumbname}"):
+ self.thumbname = f"{sub_dirname}/.thumbnails/{sub_thumbname}"
+ have_subthumb = True
+ if os.path.exists(f"{sub_dirname}/.thumbnails/{sub_filename}.p.jpg"):
+ self.jpegname = f"{sub_dirname}/.thumbnails/{sub_filename}.p.jpg"
+
+ if not have_subthumb:
+ thumb_filename = filename.replace("/", "-")
+ self.thumbname = f".thumbnails/{thumb_filename}"
+ if not self.thumbname.lower().endswith((".jpeg", ".jpg")):
+ self.thumbname += ".jpg"
+
+ if not have_thumbnail.pop(self.thumbname, False):
+ if not filename.lower().endswith((".cr2", ".cr3", ".rw2")):
+ im = rotate_image(im, self.exif_tag)
+
+ im.thumbnail((self.size * 4, self.size * 2))
+ im = im.convert("RGB")
+ im.save(self.thumbname, "JPEG")
+
+ if filename.lower().endswith((".cr2", ".cr3", ".rw2")):
+ try:
+ jpegname = f".thumbnails/{thumb_filename}.p.jpg"
+ subprocess.run(
+ [
+ "exiftool",
+ "-quiet",
+ "-binary",
+ "-tagOut!",
+ jpegname,
+ "-PreviewImage",
+ filename,
+ ]
+ )
+ # JpgFromRaw tends to have higher resolution, so overwrite PreviewImage if it is present
+ subprocess.run(
+ [
+ "exiftool",
+ "-quiet",
+ "-binary",
+ "-tagOut!",
+ jpegname,
+ "-JpgFromRaw",
+ filename,
+ ]
+ )
+ self.jpegname = jpegname
+ rotate_preview(jpegname, self.exif_tag)
+ except FileNotFoundError:
+ pass
+ elif have_thumbnail.pop(f".thumbnails/{thumb_filename}.p.jpg", None):
+ self.jpegname = f".thumbnails/{thumb_filename}.p.jpg"
if args.with_detail_page and 0:
self.average_color = im.resize((1, 1)).getpixel((0, 0))
@@ -518,10 +568,12 @@ class Thumbnail:
global location_cache
global geocoder
- latlon = f"{lat:.3f}/{lon:.3f}"
+ latlon = f"{lat:.4f}/{lon:.4f}"
- if latlon in location_cache:
- self.gps = GPSData(lat, lon, location_cache[latlon])
+ if str(args.nominatim_zoom) in location_cache.get(latlon, dict()):
+ self.gps = GPSData(
+ lat, lon, location_cache[latlon][str(args.nominatim_zoom)]
+ )
self.html.set_gps(self.gps)
return
@@ -534,7 +586,9 @@ class Thumbnail:
try:
res = geocoder.reverse((lat, lon), zoom=args.nominatim_zoom)
location = res.address.split(",")[0]
- location_cache[latlon] = location
+ if latlon not in location_cache:
+ location_cache[latlon] = dict()
+ location_cache[latlon][str(args.nominatim_zoom)] = location
except TypeError as e:
location = latlon
@@ -618,18 +672,22 @@ def copy_files(base_dir):
def write_gallery(
- file_buf, filename, thumbnails, group=None, files=list(), this_file=None
+ file_buf,
+ filename,
+ thumbnails,
+ group=None,
+ this_file=None,
+ prev_file=None,
+ next_file=None,
):
- if files:
+ if prev_file or next_file:
nav_buf = '<div class="nav">'
- for link_target in files:
- link_class = ""
- if link_target == this_file:
- link_class = "this-file"
- nav_buf += (
- f'<a class="{link_class}" href="{link_target}.html">{link_target}</a>\n'
- )
+ if prev_file:
+ nav_buf += f'<a href="{prev_file}-r.html">{prev_file}</a>\n'
+ nav_buf += f'<a class="this-file" href="{this_file}.html">{this_file}</a>\n'
+ if next_file:
+ nav_buf += f'<a href="{next_file}.html">{next_file}</a>\n'
nav_buf += "</div>"
file_buf += nav_buf
@@ -640,7 +698,14 @@ def write_gallery(
prev_heading = thumbnail.group_key
file_buf += thumbnail.to_html(i, args.with_detail_page)
- if files:
+ if prev_file or next_file:
+ nav_buf = '<div class="nav">'
+ if prev_file:
+ nav_buf += f'<a href="{prev_file}-r.html">{prev_file}</a>\n'
+ nav_buf += f'<a class="this-file" href="{this_file}.html">{this_file}</a>\n'
+ if next_file:
+ nav_buf += f'<a href="{next_file}.html">{next_file}</a>\n'
+ nav_buf += "</div>"
file_buf += nav_buf
with open(f"{base_dir}/share/html_end", "r") as f:
@@ -700,6 +765,7 @@ if __name__ == "__main__":
default=16,
help="Zoom Level for reverse geocoding",
)
+ parser.add_argument("--quiet", action="store_true", help="Do not show progress bar")
parser.add_argument(
"--resize",
metavar="N",
@@ -748,9 +814,17 @@ if __name__ == "__main__":
os.makedirs(".thumbnails", exist_ok=True)
+ rm_thumbnail = dict(
+ map(lambda k: (".thumbnails/" + k, 1), os.listdir(".thumbnails"))
+ )
+
if not args.cdn:
copy_files(f"{base_dir}/share")
+ if args.with_nominatim and os.path.exists(".thumbnails/location_cache.json"):
+ with open(".thumbnails/location_cache.json", "r") as f:
+ location_cache = json.load(f)
+
with open(f"{base_dir}/share/html_start", "r") as f:
html_buf = f.read().replace("<!-- $title -->", args.title)
@@ -766,7 +840,12 @@ if __name__ == "__main__":
filenames = args.images
thumbnails = list()
- for i, filename in enumerate(ProgressBar(max=len(filenames)).iter(filenames)):
+ if args.quiet:
+ file_iter = filenames
+ else:
+ file_iter = ProgressBar(max=len(filenames)).iter(filenames)
+
+ for i, filename in enumerate(file_iter):
try:
im = Image.open(filename)
except PIL.UnidentifiedImageError:
@@ -830,6 +909,7 @@ if __name__ == "__main__":
with_gps=args.with_nominatim,
group_key_template=args.group,
file_key_template=args.group_files,
+ have_thumbnail=rm_thumbnail,
)
thumbnails.append(thumbnail)
@@ -877,6 +957,9 @@ if __name__ == "__main__":
+ [filename]
)
+ for rm_file in rm_thumbnail.keys():
+ os.remove(rm_file)
+
if args.sort == "time":
thumbnails = list(
sorted(thumbnails, key=lambda t: t.exif_dt, reverse=args.reverse)
@@ -886,6 +969,16 @@ if __name__ == "__main__":
for thumbnail in thumbnails:
with open(f"{base_dir}/share/html_detail_start", "r") as f:
detail_html_start = f.read()
+ if args.cdn:
+ detail_html_start = detail_html_start.replace(
+ 'href=".data/css/', f'href="{args.cdn}/css/'
+ )
+ detail_html_start = detail_html_start.replace(
+ 'src=".data/js/', f'src="{args.cdn}/js/'
+ )
+ detail_html_start = detail_html_start.replace(
+ "path = '.data/css/'", f"path = '{args.cdn}/css/'"
+ )
with open(f"{base_dir}/share/html_detail_end", "r") as f:
detail_html_end = f.read()
for thumbnail in thumbnails:
@@ -893,14 +986,32 @@ if __name__ == "__main__":
write_gallery(html_buf, "index.html", thumbnails, group=args.group)
+ if args.with_nominatim:
+ with open(".thumbnails/location_cache.json", "w") as f:
+ json.dump(location_cache, f)
+
if args.group_files != "none":
thumbnail_keys = list(sorted(set(map(lambda t: t.file_key, thumbnails))))
- for thumbnail_key in thumbnail_keys:
+ for i, thumbnail_key in enumerate(thumbnail_keys):
+ prev_key = i > 0 and thumbnail_keys[i - 1] or None
+ next_key = i + 1 < len(thumbnail_keys) and thumbnail_keys[i + 1] or None
write_gallery(
html_buf,
f"{thumbnail_key}.html",
list(filter(lambda t: t.file_key == thumbnail_key, thumbnails)),
group=args.group,
- files=thumbnail_keys,
this_file=thumbnail_key,
+ prev_file=prev_key,
+ next_file=next_key,
+ )
+ write_gallery(
+ html_buf,
+ f"{thumbnail_key}-r.html",
+ reversed(
+ list(filter(lambda t: t.file_key == thumbnail_key, thumbnails))
+ ),
+ group=args.group,
+ this_file=thumbnail_key,
+ prev_file=prev_key,
+ next_file=next_key,
)
diff --git a/share/html_start b/share/html_start
index 68be715..c44b353 100644
--- a/share/html_start
+++ b/share/html_start
@@ -16,21 +16,8 @@
old.href = path;
}
}
- var otherTheme = {
- 'dark': 'light',
- 'light': 'dark',
- };
- var currentTheme = localStorage.getItem('theme');
- if (!otherTheme.hasOwnProperty(currentTheme)) {
- currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
- }
+ const currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
addStyleSheet(currentTheme, 'theme');
-
- function toggleTheme() {
- currentTheme = otherTheme[currentTheme] || 'light';
- localStorage.setItem('theme', currentTheme);
- addStyleSheet(currentTheme, 'theme');
- }
</script>
<script src=".data/js/glightbox.min.js"></script>
</head>