6 Commits

38 changed files with 378 additions and 144 deletions

View File

@@ -1 +1 @@
2.7.2 2.8.0

View File

@@ -38,8 +38,8 @@
"-n", "-n",
"-m", "-m",
"--reverse-sort", "--reverse-sort",
// "--regenerate-thumbnails", "--regenerate-thumbnails",
// "--reread-metadata", "--reread-metadata",
"--folderthumbnails" "--folderthumbnails"
], ],
"console": "integratedTerminal", "console": "integratedTerminal",

View File

@@ -176,6 +176,7 @@ figure {
.tooltip .tagdropdown { .tooltip .tagdropdown {
padding: 0; padding: 0;
margin: 0;
} }
.tooltip:hover .tooltiptext { .tooltip:hover .tooltiptext {
@@ -196,6 +197,11 @@ figure {
padding: 0; padding: 0;
} }
.tooltip .tooltiptext ol {
margin-left: 0;
padding-left: 0.5em;
}
.tooltip .tooltiptext .tagentry label { .tooltip .tooltiptext .tagentry label {
cursor: pointer; cursor: pointer;
width: 100%; width: 100%;

View File

@@ -5,6 +5,7 @@ import fnmatch
import json import json
from typing import Any from typing import Any
from datetime import datetime from datetime import datetime
from collections import defaultdict
from tqdm.auto import tqdm from tqdm.auto import tqdm
from PIL import Image, ExifTags, TiffImagePlugin, UnidentifiedImageError from PIL import Image, ExifTags, TiffImagePlugin, UnidentifiedImageError
@@ -97,8 +98,32 @@ def initialize_metadata(folder: str) -> dict[str, dict[str, int]]:
# remove old sizelist if it exists # remove old sizelist if it exists
sizelist_path = os.path.join(folder, ".sizelist.json") sizelist_path = os.path.join(folder, ".sizelist.json")
if os.path.exists(sizelist_path): if os.path.exists(sizelist_path):
with open(sizelist_path, "r") as sizelist:
metadata = json.loads(sizelist.read())
logger.warning("found old .sizelist.json, removing it...", extra={"path": sizelist_path}) logger.warning("found old .sizelist.json, removing it...", extra={"path": sizelist_path})
os.remove(sizelist_path) os.remove(sizelist_path)
# convert from old metadata format
if "images" not in metadata and "subfolders" not in metadata:
images = metadata.copy()
metadata = {}
metadata["images"] = images
elif "images" not in metadata:
metadata["images"] = {}
for k, v in metadata["images"].items():
if "width" in v:
metadata["images"][k]["w"] = v["width"]
del metadata["images"][k]["width"]
if "height" in v:
metadata["images"][k]["h"] = v["height"]
del metadata["images"][k]["height"]
if "tags" not in v:
metadata["images"][k]["tags"] = []
if "exifdata" not in v:
metadata["images"][k]["exifdata"] = None
if "xmp" not in v:
metadata["images"][k]["xmp"] = None
return metadata return metadata
@@ -143,7 +168,7 @@ def get_image_info(item: str, folder: str) -> dict[str, Any]:
except UnidentifiedImageError: except UnidentifiedImageError:
logger.error("cannot identify image file", extra={"file": file}) logger.error("cannot identify image file", extra={"file": file})
print(f"cannot identify image file: {file}") print(f"cannot identify image file: {file}")
return {"width": None, "height": None, "tags": None, "exifdata": None, "xmp": None} return {"w": None, "h": None, "tags": None, "exifdata": None, "xmp": None}
if exif: if exif:
logger.info("extracting EXIF data", extra={"file": file}) logger.info("extracting EXIF data", extra={"file": file})
ifd = exif.get_ifd(ExifTags.IFD.Exif) ifd = exif.get_ifd(ExifTags.IFD.Exif)
@@ -189,23 +214,64 @@ def get_image_info(item: str, folder: str) -> dict[str, Any]:
tags = xmpdata["xmpmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"] tags = xmpdata["xmpmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"]
if isinstance(tags, str): if isinstance(tags, str):
tags = [tags] tags = [tags]
xmp = xmpdata
except TypeError: except TypeError:
... pass
except KeyError: except KeyError:
... pass
try: try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"] tags = xmpdata["xapmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"]
if isinstance(tags, str): if isinstance(tags, str):
tags = [tags] tags = [tags]
xmp = xmpdata
except TypeError: except TypeError:
... pass
except KeyError: except KeyError:
... pass
try:
tags = xmpdata["xmpmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
if None in tags: if None in tags:
tags.remove(None) tags.remove(None)
return {"width": width, "height": height, "tags": tags, "exifdata": exifdata, "xmp": xmp} return {"w": width, "h": height, "tags": tags, "exifdata": exifdata, "xmp": xmp}
def nested_dict():
return defaultdict(nested_dict)
def insert_path(d, path):
for part in path[:-1]:
d = d[part]
last = path[-1]
if not isinstance(d[last], dict):
d[last] = {}
def finalize(d):
if isinstance(d, defaultdict):
# Sort keys before recursion
return {k: finalize(d[k]) for k in sorted(d)}
return d or []
def parse_hierarchical_tags(tags, delimiter="|"):
tree = nested_dict()
for tag in tags:
parts = tag.split(delimiter)
insert_path(tree, parts)
return finalize(tree)
def get_tags(sidecarfile: str) -> list[str]: def get_tags(sidecarfile: str) -> list[str]:
@@ -228,17 +294,33 @@ def get_tags(sidecarfile: str) -> list[str]:
if isinstance(tags, str): if isinstance(tags, str):
tags = [tags] tags = [tags]
except TypeError: except TypeError:
... pass
except KeyError: except KeyError:
... pass
try: try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"] tags = xmpdata["xapmeta"]["RDF"]["Description"]["subject"]["Bag"]["li"]
if isinstance(tags, str): if isinstance(tags, str):
tags = [tags] tags = [tags]
except TypeError: except TypeError:
... pass
except KeyError: except KeyError:
... pass
try:
tags = xmpdata["xmpmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
try:
tags = xmpdata["xapmeta"]["RDF"]["Description"]["hierarchicalSubject"]["Bag"]["li"]
if isinstance(tags, str):
tags = [tags]
except TypeError:
pass
except KeyError:
pass
if None in tags: if None in tags:
tags.remove(None) tags.remove(None)
return tags return tags
@@ -260,25 +342,23 @@ def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: d
dict[str, Any]: dictionary containing image details for HTML rendering. dict[str, Any]: dictionary containing image details for HTML rendering.
""" """
extsplit = os.path.splitext(item) extsplit = os.path.splitext(item)
if item not in metadata or _args.reread_metadata: if item not in metadata["images"] or _args.reread_metadata:
metadata[item] = get_image_info(item, folder) metadata["images"][item] = get_image_info(item, folder)
sidecarfile = os.path.join(folder, item + ".xmp") sidecarfile = os.path.join(folder, item + ".xmp")
if os.path.exists(sidecarfile): if os.path.exists(sidecarfile):
logger.info("xmp sidecar file found", extra={"file": sidecarfile}) logger.info("xmp sidecar file found", extra={"file": sidecarfile})
try: try:
metadata[item]["tags"] = get_tags(sidecarfile) metadata["images"][item]["tags"] = get_tags(sidecarfile)
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
image = { image = {
"url": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}", "src": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}",
"thumbnail": f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}.jpg", "msrc": f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}.jpg",
"name": item, "name": item,
"width": metadata[item]["width"], "w": metadata["images"][item]["w"],
"height": metadata[item]["height"], "h": metadata["images"][item]["h"],
"tags": metadata[item]["tags"], "tags": metadata["images"][item]["tags"],
"exifdata": metadata[item].get("exifdata", ""),
"xmp": metadata[item].get("xmp", ""),
} }
path = os.path.join(_args.root_directory, ".thumbnails", baseurl, item + ".jpg") path = os.path.join(_args.root_directory, ".thumbnails", baseurl, item + ".jpg")
if not os.path.exists(path) or _args.regenerate_thumbnails: if not os.path.exists(path) or _args.regenerate_thumbnails:
@@ -296,10 +376,13 @@ def process_image(item: str, folder: str, _args: Args, baseurl: str, metadata: d
else: else:
logger.info("raw file found", extra={"file": file, "extension": _raw}) logger.info("raw file found", extra={"file": file, "extension": _raw})
image["raw"] = url image["raw"] = url
return image
metadata["images"][item].update(image)
return image, metadata
def generate_html(folder: str, title: str, _args: Args, raw: list[str], version: str, logo) -> None: def generate_html(folder: str, title: str, _args: Args, raw: list[str], version: str, logo) -> list[str]:
""" """
Generates HTML content for a folder of images. Generates HTML content for a folder of images.
@@ -315,15 +398,23 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
logger.info("removing .metadata.json", extra={"folder": folder}) logger.info("removing .metadata.json", extra={"folder": folder})
os.remove(os.path.join(folder, ".metadata.json")) os.remove(os.path.join(folder, ".metadata.json"))
metadata = initialize_metadata(folder) metadata = initialize_metadata(folder)
if _args.reverse_sort:
items = sorted(os.listdir(folder), reverse=True)
else:
items = sorted(os.listdir(folder)) items = sorted(os.listdir(folder))
contains_files = False contains_files = False
images = [] images = []
subfolders = [] subfolders = []
subfoldertags = []
foldername = folder.removeprefix(_args.root_directory) foldername = folder.removeprefix(_args.root_directory)
foldername = f"{foldername}/" if foldername else "" foldername = f"{foldername}/" if foldername else ""
baseurl = urllib.parse.quote(foldername) baseurl = urllib.parse.quote(foldername)
gone = [item for item in metadata["images"] if item not in items]
for gon in gone:
del metadata["images"][gon]
create_thumbnail_folder(foldername, _args.root_directory) create_thumbnail_folder(foldername, _args.root_directory)
logger.info("processing contents", extra={"folder": folder}) logger.info("processing contents", extra={"folder": folder})
@@ -331,11 +422,12 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
for item in tqdm(items, total=len(items), desc=f"Getting image infos - {folder}", unit="files", ascii=True, dynamic_ncols=True): for item in tqdm(items, total=len(items), desc=f"Getting image infos - {folder}", unit="files", ascii=True, dynamic_ncols=True):
if item not in EXCLUDES and not item.startswith("."): if item not in EXCLUDES and not item.startswith("."):
if os.path.isdir(os.path.join(folder, item)): if os.path.isdir(os.path.join(folder, item)):
process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo) subfoldertags = process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo)
else: else:
contains_files = True contains_files = True
if os.path.splitext(item)[1].lower() in _args.file_extensions: if os.path.splitext(item)[1].lower() in _args.file_extensions:
images.append(process_image(item, folder, _args, baseurl, metadata, raw)) img, metadata = process_image(item, folder, _args, baseurl, metadata, raw)
images.append(img)
if item == "info": if item == "info":
process_info_file(folder, item) process_info_file(folder, item)
if item == "LICENSE": if item == "LICENSE":
@@ -344,24 +436,27 @@ def generate_html(folder: str, title: str, _args: Args, raw: list[str], version:
for item in items: for item in items:
if item not in EXCLUDES and not item.startswith("."): if item not in EXCLUDES and not item.startswith("."):
if os.path.isdir(os.path.join(folder, item)): if os.path.isdir(os.path.join(folder, item)):
process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo) subfoldertags = process_subfolder(item, folder, baseurl, subfolders, _args, raw, version, logo)
else: else:
contains_files = True contains_files = True
if os.path.splitext(item)[1].lower() in _args.file_extensions: if os.path.splitext(item)[1].lower() in _args.file_extensions:
images.append(process_image(item, folder, _args, baseurl, metadata, raw)) img, metadata = process_image(item, folder, _args, baseurl, metadata, raw)
images.append(img)
if item == "info": if item == "info":
process_info_file(folder, item) process_info_file(folder, item)
if item == "LICENSE": if item == "LICENSE":
process_license(folder, item) process_license(folder, item)
metadata["subfolders"] = subfolders
update_metadata(metadata, folder) update_metadata(metadata, folder)
if should_generate_html(images, contains_files, _args): if should_generate_html(images, contains_files, _args):
create_html_file(folder, title, foldername, images, subfolders, _args, version, logo) subfoldertags = create_html_file(folder, title, foldername, images, subfolders, _args, version, logo, subfoldertags)
else: else:
if os.path.exists(os.path.join(folder, "index.html")): if os.path.exists(os.path.join(folder, "index.html")):
logger.info("removing existing index.html", extra={"folder": folder}) logger.info("removing existing index.html", extra={"folder": folder})
os.remove(os.path.join(folder, "index.html")) os.remove(os.path.join(folder, "index.html"))
return subfoldertags
def create_thumbnail_folder(foldername: str, root_directory: str) -> None: def create_thumbnail_folder(foldername: str, root_directory: str) -> None:
@@ -378,7 +473,7 @@ def create_thumbnail_folder(foldername: str, root_directory: str) -> None:
os.mkdir(thumbnails_path) os.mkdir(thumbnails_path)
def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dict[str, str | None]], _args: Args, raw: list[str], version: str, logo: str) -> None: def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dict[str, str | None]], _args: Args, raw: list[str], version: str, logo: str) -> list[str]:
""" """
Processes a subfolder. Processes a subfolder.
@@ -404,10 +499,11 @@ def process_subfolder(item: str, folder: str, baseurl: str, subfolders: list[dic
else: else:
thumb = f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}/{urllib.parse.quote(thumbitems[0])}.jpg" thumb = f"{_args.web_root_url}.thumbnails/{baseurl}{urllib.parse.quote(item)}/{urllib.parse.quote(thumbitems[0])}.jpg"
subfolders.append({"url": subfolder_url, "name": item, "thumb": thumb}) subfolders.append({"url": subfolder_url, "name": item, "thumb": thumb, "metadata": f"{_args.web_root_url}{baseurl}{urllib.parse.quote(item)}/.metadata.json"})
if item not in _args.exclude_folders: if item not in _args.exclude_folders:
if not any(fnmatch.fnmatchcase(os.path.join(folder, item), exclude) for exclude in _args.exclude_folders): if not any(fnmatch.fnmatchcase(os.path.join(folder, item), exclude) for exclude in _args.exclude_folders):
generate_html(os.path.join(folder, item), os.path.join(folder, item).removeprefix(_args.root_directory), _args, raw, version, logo) return generate_html(os.path.join(folder, item), os.path.join(folder, item).removeprefix(_args.root_directory), _args, raw, version, logo)
return []
def process_license(folder: str, item: str) -> None: def process_license(folder: str, item: str) -> None:
@@ -452,7 +548,9 @@ def should_generate_html(images: list[dict[str, Any]], contains_files, _args: Ar
return images or (_args.use_fancy_folders and not contains_files) or (_args.use_fancy_folders and _args.ignore_other_files) return images or (_args.use_fancy_folders and not contains_files) or (_args.use_fancy_folders and _args.ignore_other_files)
def create_html_file(folder: str, title: str, foldername: str, images: list[dict[str, Any]], subfolders: list[dict[str, str]], _args: Args, version: str, logo: str) -> None: def create_html_file(
folder: str, title: str, foldername: str, images: list[dict[str, Any]], subfolders: list[dict[str, str]], _args: Args, version: str, logo: str, subfoldertags: list[str]
) -> list[str]:
""" """
Creates the HTML file using the template. Creates the HTML file using the template.
@@ -485,9 +583,9 @@ def create_html_file(folder: str, title: str, foldername: str, images: list[dict
alltags = set() alltags = set()
for img in images: for img in images:
for tag in img["tags"]: alltags.update(img["tags"])
alltags.add(tag)
alltags = sorted(alltags) alltags.update(set(subfoldertags))
folder_info = info.get(urllib.parse.quote(folder), "").split("\n") folder_info = info.get(urllib.parse.quote(folder), "").split("\n")
_info = [i for i in folder_info if len(i) > 1] if folder_info else None _info = [i for i in folder_info if len(i) > 1] if folder_info else None
@@ -531,19 +629,28 @@ def create_html_file(folder: str, title: str, foldername: str, images: list[dict
header=header, header=header,
license=license_info, license=license_info,
subdirectories=subfolders, subdirectories=subfolders,
images=images,
info=_info, info=_info,
webmanifest=_args.generate_webmanifest, webmanifest=_args.generate_webmanifest,
version=version, version=version,
logo=logo, logo=logo,
licensefile=license_url, licensefile=license_url,
tags=alltags, tags=parse_hierarchical_tags(alltags),
) )
with open(html_file, "w", encoding="utf-8") as f: with open(html_file, "w", encoding="utf-8") as f:
logger.info("writing html file", extra={"path": html_file}) logger.info("writing html file", extra={"path": html_file})
f.write(content) f.write(content)
if len(subfoldertags) > 1 and len(alltags) > 1:
alltags.update(set(subfoldertags))
return sorted(alltags)
elif len(subfoldertags) > 1:
return sorted(subfoldertags)
elif len(alltags) > 1:
return sorted(alltags)
else:
return []
def list_folder(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[tuple[str, str, str]]: def list_folder(folder: str, title: str, _args: Args, raw: list[str], version: str, logo: str) -> list[tuple[str, str, str]]:
""" """

View File

@@ -52,7 +52,7 @@
background-color: var(--color2); background-color: var(--color2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color4); background-color: var(--color4);
} }

View File

@@ -1,3 +1,17 @@
{%- macro render_tags(tag_tree, parent) -%}
<ol>
{%- for key, value in tag_tree.items() %}
<li class="tagentry">
<label onclick="filter()" title="{{ key }}" id="{{ parent }}|{{ key }}">
<input class="tag" type="checkbox" />{{ key }}
</label>
{%- if value %}
{{ render_tags(value, parent + '|' + key) }}
{%- endif %}
</li>
{%- endfor %}
</ol>
{%- endmacro -%}
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
@@ -21,12 +35,10 @@
<link rel="preload" href="{{ root }}.static/pswp/default-skin/default-skin.css" as="style"> <link rel="preload" href="{{ root }}.static/pswp/default-skin/default-skin.css" as="style">
<link rel="modulepreload" href="{{ root }}.static/pswp/photoswipe.min.js"> <link rel="modulepreload" href="{{ root }}.static/pswp/photoswipe.min.js">
<link rel="modulepreload" href="{{ root }}.static/pswp/photoswipe-ui-default.min.js"> <link rel="modulepreload" href="{{ root }}.static/pswp/photoswipe-ui-default.min.js">
{%- if images %}
<link rel="stylesheet" href="{{ root }}.static/pswp/photoswipe.css"> <link rel="stylesheet" href="{{ root }}.static/pswp/photoswipe.css">
<link rel="stylesheet" href="{{ root }}.static/pswp/default-skin/default-skin.css"> <link rel="stylesheet" href="{{ root }}.static/pswp/default-skin/default-skin.css">
<script src="{{ root }}.static/pswp/photoswipe.min.js"></script> <script src="{{ root }}.static/pswp/photoswipe.min.js"></script>
<script src="{{ root }}.static/pswp/photoswipe-ui-default.min.js"></script> <script src="{{ root }}.static/pswp/photoswipe-ui-default.min.js"></script>
{%- endif %}
</head> </head>
<body> <body>
@@ -49,15 +61,19 @@
<li class="title"><span class="header">{{ header }}</span></li> <li class="title"><span class="header">{{ header }}</span></li>
</div> </div>
<div class="navright"> <div class="navright">
{%- if tags|length > 0 %} {% if tags %}
<li class="tooltip"><a>Filter by Tags</a> <li class="tooltip">
<a>Filter by Tags</a>
<ol class="tooltiptext tagdropdown" id="tagdropdown"> <ol class="tooltiptext tagdropdown" id="tagdropdown">
{%- for tag in tags -%} <span class="tagentry">
<li class="tagentry"><label onclick="filter()"><input type="checkbox" />{{ tag }}</label></li><br /> <label onclick="recursive()">
{%- endfor -%} <input type="checkbox" id="recursive" />recursive filter
</label>
</span>
{{ render_tags(tags, '') }}
</ol> </ol>
</li> </li>
{%- endif %} {% endif %}
{%- if licensefile %} {%- if licensefile %}
<li class="license"><a href="{{ licensefile }}">License</a></li> <li class="license"><a href="{{ licensefile }}">License</a></li>
{%- endif %} {%- endif %}
@@ -82,27 +98,8 @@
</div> </div>
{%- endif %} {%- endif %}
</div> </div>
{% if images %}
{%- set ns = namespace(count = 0) -%}
<div class="row" id="imagelist"> <div class="row" id="imagelist">
{%- for image in images %}
<div class="column">
<figure>
<img src="{{ image.thumbnail }}" alt="{{ image.name }}" onclick="openSwipe({{ ns.count }})" onmouseover="prefetch({{ ns.count }})" onmouseleave="cancel({{ ns.count }})" />
{%- set ns.count = ns.count + 1 %}
<figcaption class="caption">{{ image.name }}
{%- if image.tiff %}
<a href="{{ image.tiff }}">TIFF</a>
{%- endif %}
{%- if image.raw %}
<a href="{{ image.raw }}">RAW</a>
{%- endif %}
</figcaption>
</figure>
</div> </div>
{%- endfor %}
</div>
{%- endif %}
{% if license %} {% if license %}
{%- if 'CC' in license.type %} {%- if 'CC' in license.type %}
<div class="footer" xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/"> <div class="footer" xmlns:cc="http://creativecommons.org/ns#" xmlns:dct="http://purl.org/dc/terms/">
@@ -123,17 +120,16 @@
{%- endif %} {%- endif %}
<span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a <span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a
href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span> href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span>
<button onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button> <button type="button" onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button>
</div> </div>
{%- endif %} {%- endif %}
{%- else %} {%- else %}
<div class="footer"> <div class="footer">
<span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a <span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a
href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span> href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span>
<button onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button> <button type="button" onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button>
</div> </div>
{%- endif %} {%- endif %}
{% if images %}
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true"> <div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">
<div class="pswp__bg"></div> <div class="pswp__bg"></div>
<div class="pswp__scroll-wrap"> <div class="pswp__scroll-wrap">
@@ -171,33 +167,86 @@
</div> </div>
</div> </div>
<script> <script>
var pswpElement = document.querySelectorAll('.pswp')[0]; const pswpElement = document.querySelectorAll('.pswp')[0];
var items = [ const re = /pid=(\d+)/;
{%- for image in images %} const filterre = /#(.*)/;
{%- if image.exifdata.DateTime %} let items = [];
{ src: "{{ image.url }}", w: {{ image.width }}, h: {{ image.height }}, msrc: "{{ image.thumbnail }}", tags: "{{ image.tags }}", title: "Captured: {{ image.exifdata.DateTime }}" }, let shown = [];
{%- else %} let subfolders = [];
{ src: "{{ image.url }}", w: {{ image.width }}, h: {{ image.height }}, msrc: "{{ image.thumbnail }}", tags: "{{ image.tags }}" }, let controllers = {};
{%- endif %} let currentFolder = "";
{%- endfor %}
];
var re = /pid=(\d+)/;
var controllers = {}
function openSwipe(img) { function requestMetadata() {
var options = { fetch(".metadata.json").then(response => {
index: img if (!response.ok) {
}; throw new Error(`HTTP error! Status: ${response.status}`);
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
} }
return response.json();
})
.then(data => {
items = Object.values(data.images);
subfolders = data.subfolders;
if (filterre.test(window.location.href)) {
var selected = window.location.href.match(filterre)[1].split(",");
setFilter(selected);
}
filter();
if (re.test(window.location.href)) { if (re.test(window.location.href)) {
var pid = window.location.href.match(re)[1]; var pid = window.location.href.match(re)[1];
openSwipe(parseInt(pid)); openSwipe(parseInt(pid));
} }
let totopbutton = document.getElementById("totop"); if (items == []) {
document.getElementById("imagelist").style.display = "none"
} else {
document.getElementById("imagelist").style.display = ""
}
})
.catch(error => console.error('Failed to fetch data:', error));
}
function openSwipe(img) {
const options = {
index: img
};
const gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, shown, options);
gallery.init();
}
async function recursive(sub = undefined) {
const ischecked = document.getElementById("recursive").checked;
const folders = document.getElementsByClassName("folders")[0];
if (sub == undefined) {
sub = subfolders;
}
if (ischecked) {
if (folders != undefined) {
folders.style.display = "none";
}
for (const folder of sub) {
currentFolder = folder.name;
try {
const response = await fetch(folder.metadata);
const data = await response.json();
if (data.subfolders.length > 0) {
await recursive(data.subfolders);
}
items = items.concat(Object.values(data.images));
filter();
} catch (error) {
console.error('Failed to fetch folder metadata:', error);
}
}
} else {
if (folders != undefined) {
folders.style.display = "";
}
requestMetadata();
}
}
const totopbutton = document.getElementById("totop");
window.onscroll = function () { scrollFunction() }; window.onscroll = function () { scrollFunction() };
@@ -213,6 +262,23 @@
window.scrollTo({ top: 0, behavior: 'smooth' }) window.scrollTo({ top: 0, behavior: 'smooth' })
} }
function updateImageList() {
let str = ""
let imagelist = document.getElementById("imagelist");
shown.forEach((item, index) => {
str += '<div class="column"><figure><img src="' + item.msrc + '" onclick="openSwipe(' + index + ')" onmouseover="prefetch(' + index + ')" onmouseleave="cancel(' + index + ')" /><figcaption class="caption">' + item.name;
if (item.tiff != "" & item.tiff != undefined) {
str += ' <a href="' + item.tiff + '">TIFF</a>';
}
if (item.raw != "" & item.raw != undefined) {
str += ' <a href="' + item.raw + '">RAW</a>';
}
str += '</figcaption></figure></div>';
});
imagelist.innerHTML = str;
}
function prefetch(img) { function prefetch(img) {
const controller = new AbortController() const controller = new AbortController()
const signal = controller.signal const signal = controller.signal
@@ -230,38 +296,59 @@
delete controllers[img]; delete controllers[img];
} }
{%- if tags|length > 0 %}
function filter() { function filter() {
var selected_tags = []; shown = [];
var tagdropdown, imagelist, figures, i, j, tags, incl;
tagdropdown = document.getElementById("tagdropdown").getElementsByTagName("li"); window.location.href = window.location.href.split("#")[0] + "#";
for (i = 0; i < tagdropdown.length; i++) {
if (tagdropdown[i].firstChild.firstChild.checked) { const selected_tags = [];
selected_tags.push([tagdropdown[i].innerText]) const tagcheckboxes = document.querySelectorAll("#tagdropdown input[class='tag']:checked");
}
} tagcheckboxes.forEach((checkbox) => {
imagelist = document.getElementById("imagelist"); const tag = checkbox.parentElement.id.trim().substring(1);
figures = imagelist.getElementsByTagName("div"); selected_tags.push(tag);
for (i = 0; i < figures.length; i++) { });
tags = items[i].tags;
incl = true; const urltags = selected_tags.join(",");
for (j = 0; j < selected_tags.length; j++) {
if (tags.indexOf(selected_tags[j]) == -1) { const isRecursiveChecked = document.getElementById("recursive").checked;
incl = false;
} for (const item of items) {
} const tags = item.tags || [];
if (incl || selected_tags == []) { const include = selected_tags.every(tag => tags.some(t => t.startsWith(tag)));
figures[i].style.display = "";
} else { if (include || selected_tags.length === 0) {
figures[i].style.display = "none"; if (isRecursiveChecked || item.folder === currentFolder) {
shown.push(item);
} }
} }
} }
filter() updateImageList();
{%- endif %} window.location.href += urltags;
}
function setFilter(selected) {
tagdropdown = document.getElementById("tagdropdown").getElementsByTagName("li");
selected.forEach((tag) => {
for (var i = 0; i < tagdropdown.length; i++) {
if (tagdropdown[i].innerText == tag) {
tagdropdown[i].firstChild.firstChild.checked = true;
}
}
});
}
function onLoad() {
requestMetadata();
}
window.addEventListener ?
window.addEventListener("load", onLoad, false) :
window.attachEvent && window.attachEvent("onload", onLoad);
</script> </script>
{%- endif %}
</body> </body>
</html> </html>

View File

@@ -54,14 +54,14 @@
{%- endif %} {%- endif %}
<span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a <span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a
href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span> href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span>
<button onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button> <button type="button" onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button>
</div> </div>
{%- endif %} {%- endif %}
{%- else %} {%- else %}
<div class="footer"> <div class="footer">
<span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a <span class="attribution">Made with <a href="https://github.com/greflm13/StaticGalleryBuilder" target="_blank" rel="noopener noreferrer">StaticGalleryBuilder {{ version }}</a> by <a
href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span> href="https://github.com/greflm13" target="_blank" rel="noopener noreferrer">{{ logo }}</a>.</span>
<button onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button> <button type="button" onclick="topFunction()" id="totop" title="Back to Top">Back to Top</button>
</div> </div>
{%- endif %} {%- endif %}
</body> </body>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC00009.jpg"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC00009.jpg">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>aqueduct</rdf:li><rdf:li>arch</rdf:li><rdf:li>arch bridge</rdf:li><rdf:li>bridge</rdf:li><rdf:li>hillside</rdf:li><rdf:li>passenger train</rdf:li><rdf:li>railroad</rdf:li><rdf:li>railroad bridge</rdf:li><rdf:li>span</rdf:li><rdf:li>train track</rdf:li><rdf:li>tree</rdf:li><rdf:li>viaduct</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|aqueduct</rdf:li><rdf:li>|arch</rdf:li><rdf:li>|arch bridge</rdf:li><rdf:li>|bridge</rdf:li><rdf:li>|hillside</rdf:li><rdf:li>|passenger train</rdf:li><rdf:li>|railroad</rdf:li><rdf:li>|railroad bridge</rdf:li><rdf:li>|span</rdf:li><rdf:li>|train track</rdf:li><rdf:li>|tree</rdf:li><rdf:li>|viaduct</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>aqueduct</rdf:li><rdf:li>arch</rdf:li><rdf:li>arch bridge</rdf:li><rdf:li>bridge</rdf:li><rdf:li>hillside</rdf:li><rdf:li>passenger train</rdf:li><rdf:li>railroad</rdf:li><rdf:li>railroad bridge</rdf:li><rdf:li>span</rdf:li><rdf:li>train track</rdf:li><rdf:li>tree</rdf:li><rdf:li>viaduct</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|aqueduct</rdf:li><rdf:li>st|arch</rdf:li><rdf:li>st|arch bridge</rdf:li><rdf:li>st|bridge</rdf:li><rdf:li>st|hillside</rdf:li><rdf:li>st|passenger train</rdf:li><rdf:li>st|railroad</rdf:li><rdf:li>st|railroad bridge</rdf:li><rdf:li>st|span</rdf:li><rdf:li>st|train track</rdf:li><rdf:li>st|tree</rdf:li><rdf:li>st|viaduct</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03470.JPG"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03470.JPG">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>bus</rdf:li><rdf:li>illuminate</rdf:li><rdf:li>neon</rdf:li><rdf:li>neon light</rdf:li><rdf:li>night</rdf:li><rdf:li>sign</rdf:li><rdf:li>train car</rdf:li><rdf:li>trolley</rdf:li><rdf:li>window</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|bus</rdf:li><rdf:li>|illuminate</rdf:li><rdf:li>|neon</rdf:li><rdf:li>|neon light</rdf:li><rdf:li>|night</rdf:li><rdf:li>|sign</rdf:li><rdf:li>|train car</rdf:li><rdf:li>|trolley</rdf:li><rdf:li>|window</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>bus</rdf:li><rdf:li>illuminate</rdf:li><rdf:li>neon</rdf:li><rdf:li>neon light</rdf:li><rdf:li>night</rdf:li><rdf:li>sign</rdf:li><rdf:li>train car</rdf:li><rdf:li>trolley</rdf:li><rdf:li>window</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|bus</rdf:li><rdf:li>st|illuminate</rdf:li><rdf:li>st|neon</rdf:li><rdf:li>st|neon light</rdf:li><rdf:li>st|night</rdf:li><rdf:li>st|sign</rdf:li><rdf:li>st|train car</rdf:li><rdf:li>st|trolley</rdf:li><rdf:li>st|window</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03508.ARW"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03508.ARW">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>pillar</rdf:li><rdf:li>display</rdf:li><rdf:li>rail</rdf:li><rdf:li>steam engine</rdf:li><rdf:li>steam locomotive</rdf:li><rdf:li>train</rdf:li><rdf:li>train car</rdf:li><rdf:li>train track</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|building</rdf:li><rdf:li>|ceiling</rdf:li><rdf:li>|pillar</rdf:li><rdf:li>|display</rdf:li><rdf:li>|rail</rdf:li><rdf:li>|steam engine</rdf:li><rdf:li>|steam locomotive</rdf:li><rdf:li>|train</rdf:li><rdf:li>|train car</rdf:li><rdf:li>|train track</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>pillar</rdf:li><rdf:li>display</rdf:li><rdf:li>rail</rdf:li><rdf:li>steam engine</rdf:li><rdf:li>steam locomotive</rdf:li><rdf:li>train</rdf:li><rdf:li>train car</rdf:li><rdf:li>train track</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|building</rdf:li><rdf:li>st|ceiling</rdf:li><rdf:li>st|pillar</rdf:li><rdf:li>st|display</rdf:li><rdf:li>st|rail</rdf:li><rdf:li>st|steam engine</rdf:li><rdf:li>st|steam locomotive</rdf:li><rdf:li>st|train</rdf:li><rdf:li>st|train car</rdf:li><rdf:li>st|train track</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03508.JPG"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC03508.JPG">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>attach</rdf:li><rdf:li>basement</rdf:li><rdf:li>beam</rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>equipment</rdf:li><rdf:li>floor</rdf:li><rdf:li>pipe</rdf:li><rdf:li>red</rdf:li><rdf:li>room</rdf:li><rdf:li>scaffold</rdf:li><rdf:li>tube</rdf:li><rdf:li>warehouse</rdf:li><rdf:li>water pipe</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|attach</rdf:li><rdf:li>|basement</rdf:li><rdf:li>|beam</rdf:li><rdf:li>|building</rdf:li><rdf:li>|ceiling</rdf:li><rdf:li>|equipment</rdf:li><rdf:li>|floor</rdf:li><rdf:li>|pipe</rdf:li><rdf:li>|red</rdf:li><rdf:li>|room</rdf:li><rdf:li>|scaffold</rdf:li><rdf:li>|tube</rdf:li><rdf:li>|warehouse</rdf:li><rdf:li>|water pipe</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>attach</rdf:li><rdf:li>basement</rdf:li><rdf:li>beam</rdf:li><rdf:li>building</rdf:li><rdf:li>ceiling</rdf:li><rdf:li>equipment</rdf:li><rdf:li>floor</rdf:li><rdf:li>pipe</rdf:li><rdf:li>red</rdf:li><rdf:li>room</rdf:li><rdf:li>scaffold</rdf:li><rdf:li>tube</rdf:li><rdf:li>warehouse</rdf:li><rdf:li>water pipe</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|attach</rdf:li><rdf:li>st|basement</rdf:li><rdf:li>st|beam</rdf:li><rdf:li>st|building</rdf:li><rdf:li>st|ceiling</rdf:li><rdf:li>st|equipment</rdf:li><rdf:li>st|floor</rdf:li><rdf:li>st|pipe</rdf:li><rdf:li>st|red</rdf:li><rdf:li>st|room</rdf:li><rdf:li>st|scaffold</rdf:li><rdf:li>st|tube</rdf:li><rdf:li>st|warehouse</rdf:li><rdf:li>st|water pipe</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="example.jpg"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="example.jpg">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|cloud</rdf:li><rdf:li>|cloudy</rdf:li><rdf:li>|evening sky</rdf:li><rdf:li>|sea</rdf:li><rdf:li>|sky</rdf:li><rdf:li>|storm cloud</rdf:li><rdf:li>|stormy</rdf:li><rdf:li>|sun</rdf:li><rdf:li>|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|cloud</rdf:li><rdf:li>st|cloudy</rdf:li><rdf:li>st|evening sky</rdf:li><rdf:li>st|sea</rdf:li><rdf:li>st|sky</rdf:li><rdf:li>st|storm cloud</rdf:li><rdf:li>st|stormy</rdf:li><rdf:li>st|sun</rdf:li><rdf:li>st|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="example.tif"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="example.tif">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|cloud</rdf:li><rdf:li>|cloudy</rdf:li><rdf:li>|evening sky</rdf:li><rdf:li>|sea</rdf:li><rdf:li>|sky</rdf:li><rdf:li>|storm cloud</rdf:li><rdf:li>|stormy</rdf:li><rdf:li>|sun</rdf:li><rdf:li>|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>evening sky</rdf:li><rdf:li>sea</rdf:li><rdf:li>sky</rdf:li><rdf:li>storm cloud</rdf:li><rdf:li>stormy</rdf:li><rdf:li>sun</rdf:li><rdf:li>sunset</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|cloud</rdf:li><rdf:li>st|cloudy</rdf:li><rdf:li>st|evening sky</rdf:li><rdf:li>st|sea</rdf:li><rdf:li>st|sky</rdf:li><rdf:li>st|storm cloud</rdf:li><rdf:li>st|stormy</rdf:li><rdf:li>st|sun</rdf:li><rdf:li>st|sunset</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

View File

Before

Width:  |  Height:  |  Size: 3.5 MiB

After

Width:  |  Height:  |  Size: 3.5 MiB

View File

@@ -2,6 +2,6 @@
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/"> <x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC01106.jpg"> <rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="DSC01106.jpg">
<dc:subject><rdf:Bag><rdf:li></rdf:li><rdf:li>clear</rdf:li><rdf:li>dark</rdf:li><rdf:li>moon</rdf:li><rdf:li>night</rdf:li><rdf:li>night sky</rdf:li><rdf:li>sky</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>|clear</rdf:li><rdf:li>|dark</rdf:li><rdf:li>|moon</rdf:li><rdf:li>|night</rdf:li><rdf:li>|night sky</rdf:li><rdf:li>|sky</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description> <dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>clear</rdf:li><rdf:li>dark</rdf:li><rdf:li>moon</rdf:li><rdf:li>night</rdf:li><rdf:li>night sky</rdf:li><rdf:li>sky</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|clear</rdf:li><rdf:li>st|dark</rdf:li><rdf:li>st|moon</rdf:li><rdf:li>st|night</rdf:li><rdf:li>st|night sky</rdf:li><rdf:li>st|sky</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF> </rdf:RDF>
</x:xmpmeta> </x:xmpmeta>

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 MiB

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/"
xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
xmpMM:DerivedFrom="000041900001.jpg">
<dc:subject>
<rdf:Bag>
<rdf:li>st</rdf:li>
<rdf:li>cloud</rdf:li>
<rdf:li>cloudy</rdf:li>
<rdf:li>fly</rdf:li>
<rdf:li>sky</rdf:li>
</rdf:Bag>
</dc:subject>
<lr:hierarchicalSubject>
<rdf:Bag>
<rdf:li>st|cloud</rdf:li>
<rdf:li>st|cloudy</rdf:li>
<rdf:li>st|fly</rdf:li>
<rdf:li>st|sky</rdf:li>
</rdf:Bag>
</lr:hierarchicalSubject>
</rdf:Description>
</rdf:RDF>
</x:xmpmeta>

Binary file not shown.

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<x:xmpmeta x:xmptk="XMP Core 4.4.0-Exiv2" xmlns:x="adobe:ns:meta/">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<rdf:Description rdf:about="" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:exif="http://ns.adobe.com/exif/1.0/" xmlns:lr="http://ns.adobe.com/lightroom/1.0/" xmlns:xmp="http://ns.adobe.com/xap/1.0/" xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/" xmpMM:DerivedFrom="000041900001.tif">
<dc:subject><rdf:Bag><rdf:li>st</rdf:li><rdf:li>cloud</rdf:li><rdf:li>cloudy</rdf:li><rdf:li>fly</rdf:li><rdf:li>sky</rdf:li></rdf:Bag></dc:subject><lr:hierarchicalSubject><rdf:Bag><rdf:li>st|cloud</rdf:li><rdf:li>st|cloudy</rdf:li><rdf:li>st|fly</rdf:li><rdf:li>st|sky</rdf:li></rdf:Bag></lr:hierarchicalSubject></rdf:Description>
</rdf:RDF>
</x:xmpmeta>

View File

@@ -97,7 +97,7 @@ body {
background-color: var(--color6); background-color: var(--color6);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color3); background-color: var(--color3);
} }

View File

@@ -96,7 +96,7 @@ body {
background-color: var(--color3); background-color: var(--color3);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color7); background-color: var(--color7);
} }

View File

@@ -74,7 +74,7 @@
background-color: var(--bcolor1); background-color: var(--bcolor1);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor3); background-color: var(--bcolor3);
} }

View File

@@ -74,7 +74,7 @@
background-color: var(--bcolor1); background-color: var(--bcolor1);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor3); background-color: var(--bcolor3);
} }

View File

@@ -79,7 +79,7 @@
font-family: "Playfair Display", serif; font-family: "Playfair Display", serif;
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color3); background-color: var(--color3);
} }

View File

@@ -73,7 +73,7 @@
background-color: var(--bcolor2); background-color: var(--bcolor2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor4); background-color: var(--bcolor4);
} }

View File

@@ -79,7 +79,7 @@
font-family: "Nunito", sans-serif; font-family: "Nunito", sans-serif;
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color4); background-color: var(--color4);
} }

View File

@@ -73,7 +73,7 @@
background-color: var(--bcolor2); background-color: var(--bcolor2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor4); background-color: var(--bcolor4);
} }

View File

@@ -52,7 +52,7 @@
background-color: var(--color3); background-color: var(--color3);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color4); background-color: var(--color4);
} }

View File

@@ -52,7 +52,7 @@
background-color: var(--color2); background-color: var(--color2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color4); background-color: var(--color4);
} }

View File

@@ -73,7 +73,7 @@
background-color: var(--bcolor2); background-color: var(--bcolor2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor4); background-color: var(--bcolor4);
} }

View File

@@ -72,7 +72,7 @@
background-color: var(--color3); background-color: var(--color3);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color2); background-color: var(--color2);
} }

View File

@@ -55,7 +55,7 @@
background-color: var(--bcolor2); background-color: var(--bcolor2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor3); background-color: var(--bcolor3);
} }

View File

@@ -76,7 +76,7 @@
background-color: var(--bcolor2); background-color: var(--bcolor2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor4); background-color: var(--bcolor4);
} }

View File

@@ -79,7 +79,7 @@
font-family: "Lora", serif; font-family: "Lora", serif;
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor3); background-color: var(--bcolor3);
} }

View File

@@ -80,7 +80,7 @@
background-color: var(--color4); background-color: var(--color4);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color3); background-color: var(--color3);
} }

View File

@@ -80,7 +80,7 @@
font-family: "Roboto", sans-serif; font-family: "Roboto", sans-serif;
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor3); background-color: var(--bcolor3);
color: var(--bcolor2); color: var(--bcolor2);
} }

View File

@@ -74,7 +74,7 @@
background-color: var(--bcolor2); background-color: var(--bcolor2);
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--bcolor4); background-color: var(--bcolor4);
} }

View File

@@ -88,7 +88,7 @@
font-family: "Montserrat", sans-serif; font-family: "Montserrat", sans-serif;
} }
.tagentry:hover { .tagentry > label:hover {
background-color: var(--color2); background-color: var(--color2);
} }