diff --git a/distribusi/README.md b/distribusi/README.md new file mode 100644 index 0000000..3e6f471 --- /dev/null +++ b/distribusi/README.md @@ -0,0 +1,98 @@ +# Distribusi CMS + +`distribusi` is a content management system for the web that produces static +index pages based on folders in the filesystem. It is inspired by the automatic +index functions featured in several web servers. It works by traversing the +file system and directory hierarchy to automatically list all the files in the +directory and providing them with html classes and tags for easy styling. + +## Requirements + +While a Pip install will pull in Python dependencies, you might need system +dependencies. This package requires two underlying packages. Those are +`python-magic`, and `pillow`. Here are the installation documentation for those +packages: + +* [github.com/threatstack/libmagic](https://github.com/threatstack/libmagic) +* [pillow.readthedocs.io](https://pillow.readthedocs.io/en/5.3.x/installation.html#external-libraries) + +## Installation + +Using [--user] or [a virtual environment] is recommended: + +[--user]: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site +[a virtual environment]: https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments + + +```bash +$ pip install --user distribusi +``` + +Note: check if the path of your local bin is added to your shell path (otherwise you cannot run distribusi from the shell directly). + +To check where distribusi is installed: + + $ find * | grep distribusi + +Add local bin to the $PATH variable: + + $ PATH=$PATH:/home/USERNAME/.local/bin/ + +## Usage + +Get help with: + +```bash +$ distribusi --help +``` + +Make a distribusi of your home folder: + +```bash +$ distribusi -d ~/ +``` + +You will find that you now have an `index.html` in every folder. + +Create a quick gallery for the web: + +``` +$ distribusi -d /path/to/my/photos -t +``` + +This creates an `index.html` with `base64` encoded thumbnails. + +Generate verbose output: + +``` +$ distribusi -v +``` + +Make an index of the archive page: + +``` +$ distribusi -d /var/www/archive/my_event -t -v +``` + +# ✌ + +## Change It + +Install [Pipenv] and then run: + +[Pipenv]: https://pipenv.readthedocs.io/en/latest/install/#installing-pipenv + +``` +$ pipenv install --dev +$ pipenv run pip install -e . +$ pipenv run distribusi --help +``` + + +## Release It + +You'll need a [PyPi](https://pypi.org/) account and to be added as a maintainer. + +``` +$ make publish +``` diff --git a/distribusi/cli.py b/distribusi/cli.py index 632ba25..bd4bd6e 100644 --- a/distribusi/cli.py +++ b/distribusi/cli.py @@ -1,6 +1,6 @@ import argparse -from distribusi.distribusi import distribusify +from distribusi import distribusify def build_argparser(): @@ -56,4 +56,8 @@ def cli_entrypoint(): else: directory = '.' + print('running distribusi ...') distribusify(args, directory) + +if __name__ == '__main__': + cli_entrypoint() \ No newline at end of file diff --git a/distribusi/distribusi.py b/distribusi/distribusi.py index 4e2a2de..4c7b6a9 100644 --- a/distribusi/distribusi.py +++ b/distribusi/distribusi.py @@ -3,30 +3,30 @@ import os from io import BytesIO import magic -from distribusi.page_template import html_footer, html_head +from page_template import html_footer, html_head, styles from PIL import Image CODE_TYPES = [ - 'x-c', - 'html' + 'x-c', + 'html' ] FILE_TYPES = { - 'image': '', - 'pdf': ( - '' - '' - ), - 'text': '{}', - 'video': ( - '' - ), - 'audio': ( - '' - ), + 'image': '', + 'pdf': ( + '' + '' + ), + 'text': '{}', + 'video': ( + '' + ), + 'audio': ( + '' + ), } @@ -34,94 +34,103 @@ MIME_TYPE = magic.Magic(mime=True) def thumbnail(image, name): - 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() - return ( - "" - ).format(name, data_url) + 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() + return ( + "" + ).format(name, data_url) def div(mime, tag, *values): - id_name = values[0].split('.')[0].replace(' ', '_') + id_name = values[0].split('.')[0].replace(' ', '_') - if 'image' in mime: - html = '
{}
{}
' - elif 'pdf' in mime: - html = '
{}
{}
' - else: - html = '
{}
' + if 'image' in mime: + html = '
{}
{}
' + elif 'pdf' in mime: + html = '
{}
{}
' + else: + html = '
{}
' - return html.format(id_name, tag, values[0]) + return html.format(id_name, tag, values[0]) def distribusify(args, directory): # noqa - for root, dirs, files in os.walk(directory): - html = [] - - if args.verbose: - print('Listing', root) - - for name in files: - if args.verbose: - print('Adding', name) - if 'index.html' not in name: - full_path = os.path.join(root, name) - mime = MIME_TYPE.from_file(full_path) - mime, format = mime.split('/') # example: plain text - - if args.verbose: - print(mime, format) - - if mime in FILE_TYPES: - # expansion for different kind of textfiles - if mime == 'text': - if name.endswith('.html') or name.endswith('.txt'): - # what types of text files to expand - a = open(full_path).read() - elif format in CODE_TYPES: - # if the plain text is code, - # which types do we wrap in pre-tags? - a = "
"+open(full_path).read()+"
" - else: - a = FILE_TYPES[mime] - - if mime == 'image' and args.thumbnail: - a = thumbnail(full_path, name) - else: - a = FILE_TYPES[mime] - - if format in FILE_TYPES: - a = FILE_TYPES[format] - - if mime not in FILE_TYPES and format not in FILE_TYPES: - # catch exceptions not defined in FILE_TYPES before - a = "{}" - if args.verbose: - message = 'mime-type not in list, adding as href: \n' - print(message, mime, format, name) - - a = a.replace('{}', name) - html.append(div(mime, a, name)) - - if root != directory: - html.append('../') - - for name in dirs: - a = "{}/".replace('{}', name) - html.append(div('dir', a, 'folder')) - - with open(os.path.join(root, 'index.html'), 'w') as f: - if not args.no_template: - f.write(html_head) - - for line in html: - f.write(line+'\n') - - if not args.no_template: - f.write(html_footer) + for root, dirs, files in os.walk(directory): + html = [] + + if args.verbose: + print('Listing', root) + + for name in files: + if args.verbose: + print('Adding', name) + if 'index.html' not in name: + full_path = os.path.join(root, name) + mime = MIME_TYPE.from_file(full_path) + mime, format = mime.split('/') # example: plain text + + if args.verbose: + print(mime, format) + + if mime in FILE_TYPES: + # expansion for different kind of textfiles + if mime == 'text': + if name.endswith('.html') or name.endswith('.txt'): + # what types of text files to expand + a = open(full_path).read() + elif format in CODE_TYPES: + # if the plain text is code, + # which types do we wrap in pre-tags? + a = "
"+open(full_path).read()+"
" + else: + a = FILE_TYPES[mime] + + if mime == 'image' and args.thumbnail: + a = thumbnail(full_path, name) + else: + a = FILE_TYPES[mime] + + if format in FILE_TYPES: + a = FILE_TYPES[format] + + if mime not in FILE_TYPES and format not in FILE_TYPES: + # catch exceptions not defined in FILE_TYPES before + a = "{}" + if args.verbose: + message = 'mime-type not in list, adding as href: \n' + print(message, mime, format, name) + + a = a.replace('{}', name) + html.append(div(mime, a, name)) + + if root != directory: + html.append('../') + position = '../' * root.count('/') + stylesheet = ''.format(position) + else: + stylesheet = ''.format(directory) + + for name in dirs: + a = "{}/".replace('{}', name) + html.append(div('dir', a, 'folder')) + + with open(os.path.join(root, 'index.html'), 'w') as f: + if not args.no_template: + header = html_head(stylesheet) + f.write(header) + + for line in html: + f.write(line+'\n') + + if not args.no_template: + f.write(html_footer) + + print('adding a stylesheet to {}'.format(directory)) + with open(os.path.join(directory, 'stylesheet.css'), 'w') as s: + s.write(styles) diff --git a/distribusi/page_template.py b/distribusi/page_template.py index 2282ced..c9f2312 100644 --- a/distribusi/page_template.py +++ b/distribusi/page_template.py @@ -1,21 +1,72 @@ -html_head = """ +def html_head(stylesheet): + header = """ - - - - - - -""" + + + + {} + + +""".format(stylesheet) + return header html_footer = """ - + """ + +styles = """ +body{ + position: absolute; + top:20px; +} + +.stylesheet{ + display: none; +} + +div{ + width: 640px; + float:left; + padding:1em; +} +div.folder, div.README{ + float: none; + padding: 0.5em 1em; +} +a.dir::before{ + content:"📁"; + font-size:18px; + padding-right: 1em; + text-decoration:none; +} +a.text::before{ + content:"☛"; + font-size:18px; + padding-right: 1em; + text-decoration:none; +} +a.back::before{ + content:"⮪"; + font-size:18px; + padding-right: 1em; + text-decoration:none; +} +a.back{ + position: fixed; + top:0; + left:0; + padding:0.5em; +} + +.image{ + max-width: 100%; +} +.pdf { + width:100%; +} +video { + width:640px; +} +""" \ No newline at end of file