Browse Source

adding a version of distribusi that work with a stylesheet file to edit the style of the index pages

master
manetta 5 years ago
parent
commit
d34cd6ec93
  1. 98
      distribusi/README.md
  2. 6
      distribusi/cli.py
  3. 209
      distribusi/distribusi.py
  4. 81
      distribusi/page_template.py

98
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
```

6
distribusi/cli.py

@ -1,6 +1,6 @@
import argparse import argparse
from distribusi.distribusi import distribusify from distribusi import distribusify
def build_argparser(): def build_argparser():
@ -56,4 +56,8 @@ def cli_entrypoint():
else: else:
directory = '.' directory = '.'
print('running distribusi ...')
distribusify(args, directory) distribusify(args, directory)
if __name__ == '__main__':
cli_entrypoint()

209
distribusi/distribusi.py

@ -3,30 +3,30 @@ import os
from io import BytesIO from io import BytesIO
import magic import magic
from distribusi.page_template import html_footer, html_head from page_template import html_footer, html_head, styles
from PIL import Image from PIL import Image
CODE_TYPES = [ CODE_TYPES = [
'x-c', 'x-c',
'html' 'html'
] ]
FILE_TYPES = { FILE_TYPES = {
'image': '<img class="image" src="{}">', 'image': '<img class="image" src="{}">',
'pdf': ( 'pdf': (
'<object data="{}" class="pdf" type="application/pdf">' '<object data="{}" class="pdf" type="application/pdf">'
'<embed src="{}" type="application/pdf" /></object>' '<embed src="{}" type="application/pdf" /></object>'
), ),
'text': '<a href="{}" class="text">{}</a>', 'text': '<a href="{}" class="text">{}</a>',
'video': ( 'video': (
'<video class="video" controls>' '<video class="video" controls>'
'<source src="{}"></source></video>' '<source src="{}"></source></video>'
), ),
'audio': ( 'audio': (
'<audio controls class="audio">' '<audio controls class="audio">'
'<source src="{}"></source></audio>' '<source src="{}"></source></audio>'
), ),
} }
@ -34,94 +34,103 @@ MIME_TYPE = magic.Magic(mime=True)
def thumbnail(image, name): def thumbnail(image, name):
size = (450, 450) size = (450, 450)
im = Image.open(image) im = Image.open(image)
im.thumbnail(size) im.thumbnail(size)
output = BytesIO() output = BytesIO()
im.save(output, format='JPEG') im.save(output, format='JPEG')
im_data = output.getvalue() im_data = output.getvalue()
data_url = base64.b64encode(im_data).decode() data_url = base64.b64encode(im_data).decode()
return ( return (
"<a href='{}'><img class='thumbnail' " "<a href='{}'><img class='thumbnail' "
"src='data:image/jpg;base64,{}'></a>" "src='data:image/jpg;base64,{}'></a>"
).format(name, data_url) ).format(name, data_url)
def div(mime, tag, *values): def div(mime, tag, *values):
id_name = values[0].split('.')[0].replace(' ', '_') id_name = values[0].split('.')[0].replace(' ', '_')
if 'image' in mime: if 'image' in mime:
html = '<div id="{}">{}<br><span class="filename">{}</span></div>' html = '<div class="{}">{}<br><span class="filename">{}</span></div>'
elif 'pdf' in mime: elif 'pdf' in mime:
html = '<div id="{}">{}<br><class="filename">{}</span></div>' html = '<div class="{}">{}<br><class="filename">{}</span></div>'
else: else:
html = '<div id="{}">{}</div>' html = '<div class="{}">{}</div>'
return html.format(id_name, tag, values[0]) return html.format(id_name, tag, values[0])
def distribusify(args, directory): # noqa def distribusify(args, directory): # noqa
for root, dirs, files in os.walk(directory): for root, dirs, files in os.walk(directory):
html = [] html = []
if args.verbose: if args.verbose:
print('Listing', root) print('Listing', root)
for name in files: for name in files:
if args.verbose: if args.verbose:
print('Adding', name) print('Adding', name)
if 'index.html' not in name: if 'index.html' not in name:
full_path = os.path.join(root, name) full_path = os.path.join(root, name)
mime = MIME_TYPE.from_file(full_path) mime = MIME_TYPE.from_file(full_path)
mime, format = mime.split('/') # example: plain text mime, format = mime.split('/') # example: plain text
if args.verbose: if args.verbose:
print(mime, format) print(mime, format)
if mime in FILE_TYPES: if mime in FILE_TYPES:
# expansion for different kind of textfiles # expansion for different kind of textfiles
if mime == 'text': if mime == 'text':
if name.endswith('.html') or name.endswith('.txt'): if name.endswith('.html') or name.endswith('.txt'):
# what types of text files to expand # what types of text files to expand
a = open(full_path).read() a = open(full_path).read()
elif format in CODE_TYPES: elif format in CODE_TYPES:
# if the plain text is code, # if the plain text is code,
# which types do we wrap in pre-tags? # which types do we wrap in pre-tags?
a = "<pre>"+open(full_path).read()+"</pre>" a = "<pre>"+open(full_path).read()+"</pre>"
else: else:
a = FILE_TYPES[mime] a = FILE_TYPES[mime]
if mime == 'image' and args.thumbnail: if mime == 'image' and args.thumbnail:
a = thumbnail(full_path, name) a = thumbnail(full_path, name)
else: else:
a = FILE_TYPES[mime] a = FILE_TYPES[mime]
if format in FILE_TYPES: if format in FILE_TYPES:
a = FILE_TYPES[format] a = FILE_TYPES[format]
if mime not in FILE_TYPES and format not in FILE_TYPES: if mime not in FILE_TYPES and format not in FILE_TYPES:
# catch exceptions not defined in FILE_TYPES before # catch exceptions not defined in FILE_TYPES before
a = "<a href='{}'>{}</a>" a = "<a href='{}'>{}</a>"
if args.verbose: if args.verbose:
message = 'mime-type not in list, adding as href: \n' message = 'mime-type not in list, adding as href: \n'
print(message, mime, format, name) print(message, mime, format, name)
a = a.replace('{}', name) a = a.replace('{}', name)
html.append(div(mime, a, name)) html.append(div(mime, a, name))
if root != directory: if root != directory:
html.append('<a href="../">../</a>') html.append('<a class="back" href="../">../</a>')
position = '../' * root.count('/')
for name in dirs: stylesheet = '<link type="text/css" rel="stylesheet" href="{}stylesheet.css" />'.format(position)
a = "<a href='{}' class='dir'>{}/</a>".replace('{}', name) else:
html.append(div('dir', a, 'folder')) stylesheet = '<link type="text/css" rel="stylesheet" href="stylesheet.css" />'.format(directory)
with open(os.path.join(root, 'index.html'), 'w') as f: for name in dirs:
if not args.no_template: a = "<a href='{}' class='dir'>{}/</a>".replace('{}', name)
f.write(html_head) html.append(div('dir', a, 'folder'))
for line in html: with open(os.path.join(root, 'index.html'), 'w') as f:
f.write(line+'\n') if not args.no_template:
header = html_head(stylesheet)
if not args.no_template: f.write(header)
f.write(html_footer)
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)

81
distribusi/page_template.py

@ -1,21 +1,72 @@
html_head = """ def html_head(stylesheet):
header = """
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<!-- Generated with distribusi https://git.vvvvvvaria.org/rra/distribusi --> <!-- Generated with distribusi https://git.vvvvvvaria.org/rra/distribusi -->
<meta http-equiv="content-type" content="text/html; charset=utf-8"> <meta http-equiv="content-type" content="text/html; charset=utf-8">
<style> {}
.image{max-width: 100%;} </head>
.pdf {width:100%;} <body>
div{width: 640px;float:left;padding:1em;} """.format(stylesheet)
video {width:640px;} return header
.dir::before{content:"📁";font-size:18px;}
</style>
</head>
<body>
"""
html_footer = """ html_footer = """
</body> </body>
</html> </html>
""" """
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;
}
"""
Loading…
Cancel
Save