From c8862dfb5980762ea0a6ac05b58b4c26ae744970 Mon Sep 17 00:00:00 2001 From: crunk Date: Wed, 4 Dec 2024 10:34:07 +0100 Subject: [PATCH] removed distribusi git submodule --- .gitmodules | 3 - distribusi | 1 - distribusi/__init__.py | 0 distribusi/cli.py | 89 ++++++++ distribusi/distribusi.py | 275 ++++++++++++++++++++++++ distribusi/mappings.py | 15 ++ distribusi/templates/__init__.py | 0 distribusi/templates/image_templates.py | 4 + distribusi/templates/page_template.py | 16 ++ requirements.txt | 1 - setup.py | 2 +- 11 files changed, 400 insertions(+), 6 deletions(-) delete mode 160000 distribusi create mode 100644 distribusi/__init__.py create mode 100644 distribusi/cli.py create mode 100644 distribusi/distribusi.py create mode 100644 distribusi/mappings.py create mode 100644 distribusi/templates/__init__.py create mode 100644 distribusi/templates/image_templates.py create mode 100644 distribusi/templates/page_template.py diff --git a/.gitmodules b/.gitmodules index eb27e09..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "distribusi"] - path = distribusi - url = https://git.vvvvvvaria.org/crunk/distribusi diff --git a/distribusi b/distribusi deleted file mode 160000 index e291e74..0000000 --- a/distribusi +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e291e7497e40211c2ebd54ca32a1f4bdaed71230 diff --git a/distribusi/__init__.py b/distribusi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/distribusi/cli.py b/distribusi/cli.py new file mode 100644 index 0000000..8f4c10c --- /dev/null +++ b/distribusi/cli.py @@ -0,0 +1,89 @@ +import argparse +import os + +from distribusi.distribusi import distribusify + + +def build_argparser(): + parser = argparse.ArgumentParser( + """ + distribusi is a content management system for the web that produces static + index pages based on folders in the files system. It is inspired by the + automatic index functions featured in several popular web servers. + distribusi works by traversing the file system and directory hierarchy to + automatically list all the files in the directory, detect the file types + and providing them with relevant html classes and tags for easy styling. + """ + ) + + parser.add_argument( + "-d", + "--directory", + help="Select which directory to distribute", + default=".", + ) + + parser.add_argument( + "-s", "--style", help="Select a CSS style sheet to include" + ) + + parser.add_argument( + "-v", + "--verbose", + help="Print verbose debug output", + action="store_true", + ) + + parser.add_argument( + "-t", + "--thumbnail", + help="Generate 450x450 thumbnails for images", + action="store_true", + ) + + parser.add_argument( + "-a", + "--alttexts", + help="Adds file alttext based on same named files", + action="store_true", + ) + + parser.add_argument( + "-r", + "--remove-index", + help="Recursively removes all instances of index.html that have been previously made by distribusi", + action="store_true", + ) + + parser.add_argument( + "-e", + "--exclude-directory", + help="Exclude one or multiple directories from indexing", + nargs="*", + metavar="DIR", + ) + + parser.add_argument( + "-f", + "--force", + help="Force whether distribusi overwrites or removes instances of index.html not generated by distribusi, use at own risk!", + action="store_true", + ) + + parser.add_argument( + "--no-hidden", help="Exclude hidden directories", action="store_true" + ) + + parser.add_argument( + "--menu-with-index", + help="Append index.html to menu items to aid navigation", + action="store_true", + ) + + return parser + + +def cli_entrypoint(): + parser = build_argparser() + args = parser.parse_args() + distribusify(args, args.directory) diff --git a/distribusi/distribusi.py b/distribusi/distribusi.py new file mode 100644 index 0000000..6b09016 --- /dev/null +++ b/distribusi/distribusi.py @@ -0,0 +1,275 @@ +import os + +import magic +from PIL import Image +from distribusi.templates.page_template import html_footer, html_head +from distribusi.templates.image_templates import ( + image_no_description, + image_with_description, + image_with_alttext, + image_full_figure, +) +from distribusi.mappings import CODE_TYPES, FILE_TYPES, SUB_TYPES + +MIME_TYPE = magic.Magic(mime=True) + + +def add_alttext(full_path_image): + try: + image_filename_no_ext = os.path.splitext(full_path_image)[0] + alttext_filename = f"{image_filename_no_ext}_alttext.txt" + return _read_matching_text_file( + image_filename_no_ext, alttext_filename + ) + except Exception as e: + print(f"exception {e} raised while making alttext") + return + + +def add_description(full_path_image): + try: + image_filename_no_ext = os.path.splitext(full_path_image)[0] + description_filename = f"{image_filename_no_ext}_dv_description.txt" + return _read_matching_text_file( + image_filename_no_ext, description_filename + ) + except Exception as e: + print(f"exception {e} raised while adding description") + return + + +def _read_matching_text_file(image_filename_no_ext, filename): + if not os.path.isfile(filename): + return + print(f"{image_filename_no_ext} has {filename}") + with open(filename, "r") as text_file: + return text_file.read() + + +def thumbnail(full_path_image, name, args): + if full_path_image.endswith("_thumbnail.jpg"): + return + try: + size = (450, 450) + thumbnail_image = Image.open(full_path_image) + thumbnail_image.thumbnail(size) + + if thumbnail_image.mode == "RGBA": + bg = Image.new("RGBA", thumbnail_image.size, (255, 255, 255)) + composite = Image.alpha_composite(bg, thumbnail_image) + thumbnail_image = composite.convert("RGB") + + image_filename_no_ext = os.path.splitext(full_path_image)[0] + thumbnail_filename = f"{image_filename_no_ext}_thumbnail.jpg" + thumbnail_image.save(thumbnail_filename, format="JPEG") + return os.path.basename(thumbnail_filename) + except Exception as e: + print("Thumbnailer:", e) + return + + +def format_div(args, type_, subtype, tag, name): + id_name = name.split(".")[0].replace(" ", "_") + filename = f'{name}' + + if "image" in type_: + html = '
{}
' + elif "pdf" in subtype: + html = '
{}' + filename + "
" + elif "dir" in type_ or "html" in subtype or "unkown-file" in subtype: + html = '
{}
' + else: + html = '
{}' + filename + "
" + + return html.format(id_name, subtype, tag) + + +def check_distribusi_index(args, index): + """ + check whether a index.html file is generated by distribusi + """ + if not args.force: + with open(index, "r") as f: + if '' in f.read(): + return True + else: + if args.verbose: + print(index, "not generated by distribusi, skipping") + return False + elif args.force: + return True + + +def write_index_html(args, index, html): + with open(index, "w") as index_file: + styled_html_head = html_head.format(cssfile=args.style) + index_file.write(styled_html_head) + for line in html: + index_file.write(line + "\n") + index_file.write(html_footer) + + +def handle_text_files(name, full_path, subtype): + if name.endswith(".html") or subtype == "html": + subtype = "html" + # what types of text files to expand + tag = '
{}
'.format( + name, open(full_path).read() + ) + elif subtype in CODE_TYPES or name.endswith(".txt"): + # if the plain text is code, + # which types do we wrap in pre-tags? + tag = "
" + open(full_path).read() + "
" + else: + subtype = subtype + " unkown-file" + tag = "{}" + # a = FILE_TYPES[type_] + return subtype, tag + + +def handle_image_files(name, full_path, args): + if args.thumbnail: + thumbnail_filename = thumbnail(full_path, name, args) + if thumbnail_filename is None: + return + + image_alttext = add_alttext(full_path) + image_description = add_description(full_path) + + if not image_alttext and not image_description: + return image_no_description.format( + name=name, thumbnail_filename=thumbnail_filename + ) + if not image_alttext: + return image_with_description.format( + name=name, + thumbnail_filename=thumbnail_filename, + image_description=image_description, + ) + if not image_description: + return image_with_alttext.format( + name=name, + thumbnail_filename=thumbnail_filename, + image_alttext=image_alttext, + ) + return image_full_figure.format( + name=name, + thumbnail_filename=thumbnail_filename, + image_alttext=image_alttext, + image_description=image_description, + ) + return FILE_TYPES["image"].format(name, image_alttext) + + +def remove_index_html(root, files, args): + index = os.path.join(root, "index.html") + if "index.html" in files: + try: + if check_distribusi_index(args, index): + if args.verbose: + print("Removing index.html from", root) + os.remove(index) + except Exception as e: + print(e) + return + + +def remove_hidden_files_and_folders(dirs, files): + dirs = list(filter(lambda d: not d.startswith("."), dirs)) + files = list(filter(lambda f: not f.startswith("."), files)) + return dirs, files + + +def is_skipped_file(name, args): + if "index.html" in name: + return True + + if name.endswith("_thumbnail.jpg"): + return True + + if name.endswith("_alttext.txt"): + return True + + if name.endswith("_dv_description.txt"): + return True + + if args.style in name: + return True + + +def distribusify(args, directory): # noqa + for root, dirs, files in os.walk(directory): + html = [] + + if args.exclude_directory: + if args.verbose: + print( + "Excluding directory:", ", ".join(args.exclude_directory) + ) + dirs[:] = [d for d in dirs if d not in args.exclude_directory] + + if args.no_hidden: + dirs, files = remove_hidden_files_and_folders(dirs, files) + + if args.remove_index: + remove_index_html(root, files, args) + + if args.verbose: + print("Generating directory listing for", root) + + for name in sorted(files): + if is_skipped_file(name, args): + continue + + full_path = os.path.join(root, name) + mime = MIME_TYPE.from_file(full_path) + type_, subtype = mime.split("/") + alttext = name + + if args.verbose: + print("Found", name, "as", mime) + if type_ in FILE_TYPES: + match type_: + case "text": + subtype, tag = handle_text_files( + name, full_path, subtype + ) + case "image": + tag = handle_image_files(name, full_path, args) + if tag is None: + continue + case _: + tag = FILE_TYPES[type_].format(name, alttext) + + if subtype in SUB_TYPES: + tag = SUB_TYPES[subtype] + + if type_ not in FILE_TYPES and subtype not in SUB_TYPES: + # catch exceptions not yet defined in FILE_TYPES or SUB_TYPES + tag = "{}" + if args.verbose: + message = ( + "not in list of file types, adding as plain href: \n" + ) + print(type_, subtype, message, name) + subtype = subtype + " unkown-file" + + tag = tag.replace("{}", name) + html.append(format_div(args, type_, subtype, tag, name)) + + if root != directory: + if args.menu_with_index: + html.append('../') + else: + html.append('../') + + for name in sorted(dirs): + if args.menu_with_index: + tag = "{}".replace("{}", name) + else: + tag = "{}/".replace("{}", name) + + html.insert(0, format_div(args, "dir", "dir", tag, "folder")) + + index = os.path.join(root, "index.html") + write_index_html(args, index, html) diff --git a/distribusi/mappings.py b/distribusi/mappings.py new file mode 100644 index 0000000..677d2a3 --- /dev/null +++ b/distribusi/mappings.py @@ -0,0 +1,15 @@ +CODE_TYPES = ["x-c", "x-shellscript", "x-python"] + +FILE_TYPES = { + "image": '{}', + "text": '{}', + "video": ("'), + "audio": (''), +} + +SUB_TYPES = { + "pdf": ( + '' + '' + ) +} diff --git a/distribusi/templates/__init__.py b/distribusi/templates/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/distribusi/templates/image_templates.py b/distribusi/templates/image_templates.py new file mode 100644 index 0000000..565f587 --- /dev/null +++ b/distribusi/templates/image_templates.py @@ -0,0 +1,4 @@ +image_no_description = '{name}' +image_with_description = '
{image_description}
' +image_with_alttext = '{image_alttext}' +image_full_figure = '
{image_alttext}
{image_description}
' diff --git a/distribusi/templates/page_template.py b/distribusi/templates/page_template.py new file mode 100644 index 0000000..5f55cc0 --- /dev/null +++ b/distribusi/templates/page_template.py @@ -0,0 +1,16 @@ +html_head = '''\ + + + + + + + + + +''' + +html_footer ='''\ + + +''' diff --git a/requirements.txt b/requirements.txt index fcfbe55..efd9a18 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,6 @@ bleach-allowlist==1.0.3 blinker==1.7.0 cffi click==8.1.7 -distribusi @ git+https://git.vvvvvvaria.org/crunk/distribusi@4654ced5e8dfe803b62bc6163fa3d88a73a9010a dnspython==2.1.0 email-validator==1.1.3 Flask==3.0.3 diff --git a/setup.py b/setup.py index ce7462a..64aeb68 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,3 @@ from setuptools import find_packages, setup -setup(name="library", version="1.0", packages=find_packages()) +setup(name="dsitribusi-verse", version="1.0", packages=find_packages())