From 3072879614b443e10ee92e9efe1af286812f1e99 Mon Sep 17 00:00:00 2001 From: Flo Greistorfer Date: Thu, 27 Jun 2024 22:52:14 +0200 Subject: [PATCH] Version 1.2: - added support for CreativeCommons Licenses (cc0, cc-by, cc-by-sa, cc-by-nd, cc-by-nc, cc-by-nc-sa, cc-by-nc-nd) - added command line option for Author - added command line option for title - added navbar --- README.md | 13 ++++- cclicense.py | 138 +++++++++++++++++++++++++++++++++++++++++++++++ generate_html.py | 84 +++++++++++++++++++++++++++-- 3 files changed, 229 insertions(+), 6 deletions(-) create mode 100644 cclicense.py diff --git a/README.md b/README.md index c94d52d..92ad24b 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ - **Folder Navigation:** The HTML files include navigation links to subfolders. - **Responsive Design:** The generated HTML uses responsive design techniques to ensure the gallery looks good on different screen sizes. - **Non-Interactive Mode:** It can run in a non-interactive mode suitable for automated workflows. +- **License Information:** Optionally include license information in the HTML files. +- **Custom Author and Title:** Allows specifying a custom author and title for the HTML files. ## Requirements @@ -29,7 +31,7 @@ pip install numpy tqdm The script supports several command-line options to customize its behavior. Below is the list of available options: ```sh -./generate_html.py [-h] [-f ROOT] [-w WEBROOT] [-i ICON] [-r] [-n] [--fancyfolders] +./generate_html.py [-h] [-f ROOT] [-w WEBROOT] [-i ICON] [-r] [-n] [--fancyfolders] [-l LICENSE] [-a AUTHOR] [-t TITLE] ``` ### Options @@ -41,6 +43,9 @@ The script supports several command-line options to customize its behavior. Belo - `-r, --regenerate`: Regenerate thumbnails even if they already exist. - `-n, --non-interactive`: Disable interactive mode, which is useful for automated workflows. - `--fancyfolders`: Use fancy folders instead of the default Apache directory listing. +- `-l LICENSE, --license LICENSE`: Specify a license for the content. Options are `cc-zero`, `cc-by`, `cc-by-sa`, `cc-by-nd`, `cc-by-nc`, `cc-by-nc-sa`, and `cc-by-nc-nd`. +- `-a AUTHOR, --author AUTHOR`: Specify the author of the content. +- `-t TITLE, --title TITLE`: Specify the title for the root directory HTML file. ### Example @@ -56,6 +61,12 @@ To regenerate thumbnails and run in non-interactive mode: ./generate_html.py -f /data/pictures -w https://pictures.example.com -r -n ``` +To include a license, author, and custom title: + +```sh +./generate_html.py -f /data/pictures -w https://pictures.example.com -l cc-by -a "John Doe" -t "My Photo Gallery" +``` + ## Notes - The root and webroot paths must point to the same folder, one on the filesystem and one on the webserver. Use absolute paths. diff --git a/cclicense.py b/cclicense.py new file mode 100644 index 0000000..9aeb0f5 --- /dev/null +++ b/cclicense.py @@ -0,0 +1,138 @@ +def licenseswitch(cclicense: str): + switch = { + "cc-zero": """ +
+ $title by $author is marked with + CC0 1.0 +
+""", + "cc-by": """ +
+ $title by $author is licensed under + CC BY 4.0 +
+""", + "cc-by-sa": """ +
+ $title by $author is licensed under + CC BY-SA 4.0 +
+""", + "cc-by-nd": """ +
+ $title by $author is licensed under + CC BY-ND 4.0 +
+""", + "cc-by-nc": """ +
+ $title by $author is licensed under + CC BY-NC 4.0 +
+""", + "cc-by-nc-sa": """ +
+ $title by $author is licensed under + CC BY-NC-SA 4.0 +
+""", + "cc-by-nc-nd": """ +
+ $title by $author is licensed under + CC BY-NC-ND 4.0 +
+""", + } + + return switch.get(cclicense, "") + + +def licenseurlswitch(cclicense: str): + switch = { + "cc-zero": "https://creativecommons.org/publicdomain/zero/1.0/", + "cc-by": "https://creativecommons.org/licenses/by/4.0/", + "cc-by-sa": "https://creativecommons.org/licenses/by-sa/4.0/", + "cc-by-nd": "https://creativecommons.org/licenses/by-nd/4.0/", + "cc-by-nc": "https://creativecommons.org/licenses/by-nc/4.0/", + "cc-by-nc-sa": "https://creativecommons.org/licenses/by-nc-sa/4.0/", + "cc-by-nc-nd": "https://creativecommons.org/licenses/by-nc-nd/4.0/", + } + + return switch.get(cclicense, "") diff --git a/generate_html.py b/generate_html.py index b214a3e..2ea9e59 100755 --- a/generate_html.py +++ b/generate_html.py @@ -9,11 +9,14 @@ from pathlib import Path import numpy as np from tqdm.auto import tqdm +import cclicense + _ROOT = "/data/pictures/" _WEBROOT = "https://pictures.example.com/" _FOLDERICON = "https://www.svgrepo.com/show/400249/folder.svg" _ROOTTITLE = "Pictures" _FAVICON = "favicon.ico" +_AUTHOR = "Author" imgext = [".jpg", ".jpeg"] rawext = [".3fr", ".ari", ".arw", ".bay", ".braw", ".crw", ".cr2", ".cr3", ".cap", ".data", ".dcs", ".dcr", ".dng", ".drf", ".eip", ".erf", ".fff", ".gpr", ".iiq", ".k25", ".kdc", ".mdc", ".mef", ".mos", ".mrw", ".nef", ".nrw", ".obm", ".orf", ".pef", ".ptx", ".pxn", ".r3d", ".raf", ".raw", ".rwl", ".rw2", ".rwz", ".sr2", ".srf", ".srw", ".tif", ".tiff", ".x3f"] excludes = [".lock", _FAVICON, "index.html", "Galleries", ".previews", "Archives"] @@ -35,6 +38,8 @@ HTMLHEADER = """ body { margin: 0; + margin-top: 32px; + margin-bottom: 56px; font-family: Arial; } @@ -50,6 +55,7 @@ HTMLHEADER = """ .folders figure { margin-bottom: 32px; + margin-top: 50px; } .header h1 { @@ -151,11 +157,63 @@ HTMLHEADER = """ width: 100%; display: block; } + + .license { + position: fixed; + bottom: 0; + width: 100%; + background-color: lightgrey; + padding: 12px; + } + + .navbar { + list-style-type: none; + margin: 0; + padding: 0; + overflow: hidden; + position: fixed; + top: 0; + width: 100%; + background-color: #333; + } + + .navbar li { + float: left; + } + + .navbar li a { + display: block; + color: white; + text-align: center; + padding: 14px 16px; + text-decoration: none; + } + + .navbar li span { + display: block; + color: white; + text-align: center; + padding: 14px 16px; + text-decoration: none; + } + + /* Change the link color to #111 (black) on hover */ + .navbar li a:hover { + background-color: #111; + } """ +NAVBAR = """ + +""" + def thumbnail_convert(arguments: tuple[str, str]): folder, item = arguments @@ -178,7 +236,8 @@ def listfolder(folder: str, title: str): if not os.path.exists(os.path.join(args.root, ".previews", folder.removeprefix(args.root))): os.mkdir(os.path.join(args.root, ".previews", folder.removeprefix(args.root))) - temp_obj = Template(HTMLHEADER) + body = Template(HTMLHEADER) + navbar = Template(NAVBAR) contains_files = False for item in items: if item not in excludes: @@ -212,9 +271,15 @@ def listfolder(folder: str, title: str): pbar.update(0) if len(images) > 0 or (args.fancyfolders and not contains_files): with open(os.path.join(folder, "index.html"), "w", encoding="utf-8") as f: - f.write(temp_obj.substitute(title=title, favicon=f"{args.root}/{_FAVICON}")) + f.write(body.substitute(title=title, favicon=f"{args.webroot}{_FAVICON}")) f.write('
\n') - f.write(f"

{title}

\n") + if folder == args.root: + f.write(f"

{os.path.basename(folder)}

\n") + else: + if args.license: + f.write(navbar.substitute(home=args.webroot, parent=f"{args.webroot}{urllib.parse.quote(folder.removeprefix(args.root).removesuffix(folder.split('/')[-1]))}", title=os.path.basename(folder), license=f'
  • License
  • \n')) + else: + f.write(navbar.substitute(home=args.webroot, parent=f"{args.webroot}{urllib.parse.quote(folder.removeprefix(args.root).removesuffix(folder.split('/')[-1]))}", title=os.path.basename(folder), license="")) f.write('
    \n') for subfolder in subfolders: f.write(subfolder) @@ -229,6 +294,8 @@ def listfolder(folder: str, title: str): f.write(f" {image}\n") f.write("
    \n") f.write("
    \n") + if args.license: + f.write(_cclicense.substitute(webroot=args.webroot, title=args.title, author=args.author)) f.write(" \n") f.close() else: @@ -261,6 +328,7 @@ def main(): global total global args global pbar + global _cclicense total = 0 # Parse command-line arguments @@ -270,6 +338,9 @@ def main(): parser.add_argument("-i", "--foldericon", help="Foldericon url", default=_FOLDERICON, required=False, type=str, dest="foldericon", metavar="ICON") parser.add_argument("-r", "--regenerate", help="Regenerate thumbnails", action="store_true", default=False, required=False, dest="regenerate") parser.add_argument("-n", "--non-interactive", help="Disable interactive mode", action="store_true", default=False, required=False, dest="non_interactive") + parser.add_argument("-l", "--license", help="License", default=None, required=False, choices=["cc-zero", "cc-by", "cc-by-sa", "cc-by-nd", "cc-by-nc", "cc-by-nc-sa", "cc-by-nc-nd"], dest="license") + parser.add_argument("-a", "--author", help="Author", default=_AUTHOR, required=False, type=str, dest="author") + parser.add_argument("-t", "--title", help="Title", default=_ROOTTITLE, required=False, type=str, dest="title") parser.add_argument("--fancyfolders", help="Use fancy folders instead of default apache ones", action="store_true", default=False, required=False, dest="fancyfolders") args = parser.parse_args() @@ -280,6 +351,9 @@ def main(): if not os.path.exists(os.path.join(args.root, ".previews")): os.mkdir(os.path.join(args.root, ".previews")) + if args.license: + _cclicense = Template(cclicense.licenseswitch(args.license)) + if os.path.exists(os.path.join(args.root, ".lock")): print("Another instance of this program is running.") exit() @@ -288,7 +362,7 @@ def main(): if args.non_interactive: print("Generating html files...") - listfolder(args.root, _ROOTTITLE) + listfolder(args.root, args.title) with Pool(os.cpu_count()) as p: print("Generating thumbnails...") @@ -299,7 +373,7 @@ def main(): pbar.close() pbar = tqdm(total=total + 1, desc="Generating html files", unit=" files", ascii=True, dynamic_ncols=True) - listfolder(args.root, _ROOTTITLE) + listfolder(args.root, args.title) pbar.close() with Pool(os.cpu_count()) as p: