import argparse
import os

from distribusi.distribusi import distribusify


def build_argparser():
    parser = argparse.ArgumentParser("""
    distbusi 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(
        '-n',
        '--no-template',
        help="Don't use the template to output html",
        action="store_true",
    )

    parser.add_argument(
        '-nf',
        '--no-filenames',
        help="Don't add file names to listing",
        action="store_true",
    )

    parser.add_argument(
        '-c',
        '--captions',
        help="Adds image captions based on EXIF metadata, requires 'exiftool'",
        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)
cli.py
import base64
import os
import subprocess
from io import BytesIO

import magic
from PIL import Image

from distribusi.page_template import html_footer, html_head
from distribusi.mappings import CODE_TYPES, FILE_TYPES, SUB_TYPES

import time

MIME_TYPE = magic.Magic(mime=True)


def the_caption(image):
    try:
        process = subprocess.Popen(
            ['exiftool', '-Comment', image], stdout=subprocess.PIPE)
        out, err = process.communicate()
    except Exception as e:
        print(e)
        print('Do you have exiftool installed?')
    try:
        caption = out.decode("utf-8").split(": ", 1)[1]
    except Exception as e:
        caption = ''
        print(e)
    return caption


def thumbnail(image, name, args):
    try:
        size = (450, 450)
        im = Image.open(image)
        im.thumbnail(size)
        output = BytesIO()
        im.save(output, format='JPEG')
        im_data = output.getvalue()
        data_url = base64.b64encode(im_data).decode()
        if args.captions:
            cap = the_caption(image)
        else:
            cap = name
        return (
            "
distribusi.py
" ).format(name, data_url, cap) except Exception as e: print('Thumbnailer:', e) return "
distribusi.py
".format(name, name, name) def div(args, type_, subtype, tag, name): id_name = name.split('.')[0].replace(' ', '_') if args.no_filenames: filename = '' else: filename = 'distribusi.py'.format(name) if 'image' in type_: html = '
distribusi.py
' elif 'pdf' in subtype: html = '
distribusi.py' + filename + '
' elif 'dir' in type_ or 'html' in subtype: html = '
distribusi.py
' else: html = '
distribusi.py' + 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(args,index, html, html_head, html_footer, root): if "Bibliotecha".lower() in root.lower(): html_head = html_head.replace("replace","bibliotecha") elif "Homebrewserver".lower() in root.lower(): html_head = html_head.replace("replace","homebrewserver") elif "Relearn".lower() in root.lower(): html_head = html_head.replace("replace","relearn") else: html_head = html_head.replace("replace","simple") with open(index, 'w') as f: if not args.no_template: if args.style: fs = open(args.style, "r") style = fs.read() styled_html_head = html_head % style else: styled_html_head = html_head % '' f.write(styled_html_head) for line in html: f.write(line + '\n') if not args.no_template: f.write(html_footer) def distribusify(args, directory): # noqa for root, dirs, files in os.walk(directory): 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 = list(filter(lambda d: not d.startswith('.'), dirs)) files = list(filter(lambda f: not f.startswith('.'), files)) dirs.sort() files.sort() if not args.remove_index: html = [] plainList = [] if args.verbose: print('Generating directory listing for', root) for name in sorted(files): if 'index.html' not in name: full_path = os.path.join(root, name) mime = MIME_TYPE.from_file(full_path) # example: MIME plain/text becomes 'type' plain 'subtype' text type_, subtype = mime.split('/') caption = name if args.verbose: print('Found', name, 'as', mime) if type_ in FILE_TYPES: a = FILE_TYPES[type_].format(name, caption) b = FILE_TYPES[type_].format(name, caption) # expansion for different kind of text files if type_ == 'text': if name.endswith('.html') or subtype == 'html': subtype = 'html' # what types of text files to expand a = '
distribusi.py
'.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? a = "
" + open(full_path).read() + "
" else: subtype = 'plain' b = "distribusi.py" b = b.replace('distribusi.py', name) plainList.append(b) # a = FILE_TYPES[type_] if type_ == 'image': if args.thumbnail: a = thumbnail(full_path, name, args) if args.no_filenames: caption = "" if args.captions: caption = the_caption(full_path) a = FILE_TYPES[type_].format(name, caption) if subtype in SUB_TYPES: a = SUB_TYPES[subtype] b = 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 b = "distribusi.py" b = b.replace('distribusi.py', name) plainList.append(b) subtype = 'plain' if args.verbose: message = 'not in list of file types, adding as plain href: \n' print(type_, subtype, message, name) if not 'plain' in subtype: a = a.replace('distribusi.py', name) html.append(div(args, type_, subtype, a, name)) if name == sorted(files)[-1]: if len(plainList)>0: b = ' '.join(plainList) html.append("
"+b+"
") if root != directory: if args.menu_with_index: html.append('../') else: html.append('../') html.insert(0, "") index = os.path.join(root, 'index.html') if os.path.exists(index): if check_distribusi_index(args, index): write_index(args,index,html, html_head, html_footer,root) elif not os.path.exists(index): write_index(args,index,html, html_head, html_footer, root) if args.remove_index: 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)
distribusi.py
CODE_TYPES = ['x-c', 'x-shellscript', 'x-python'] FILE_TYPES = { 'image': '
mappings.py
', 'text': 'mappings.py', 'video': (''), 'audio': (''), } SUB_TYPES = { 'pdf': ( '' '') }
html_head = """ """ html_footer = """ """
__init__.py
../