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

This commit is contained in:
manetta 2019-06-11 15:07:53 +02:00
parent 870aa07839
commit d34cd6ec93
4 changed files with 265 additions and 103 deletions

98
distribusi/README.md Normal file
View File

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

View File

@ -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()

View File

@ -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': '<img class="image" src="{}">',
'pdf': (
'<object data="{}" class="pdf" type="application/pdf">'
'<embed src="{}" type="application/pdf" /></object>'
),
'text': '<a href="{}" class="text">{}</a>',
'video': (
'<video class="video" controls>'
'<source src="{}"></source></video>'
),
'audio': (
'<audio controls class="audio">'
'<source src="{}"></source></audio>'
),
'image': '<img class="image" src="{}">',
'pdf': (
'<object data="{}" class="pdf" type="application/pdf">'
'<embed src="{}" type="application/pdf" /></object>'
),
'text': '<a href="{}" class="text">{}</a>',
'video': (
'<video class="video" controls>'
'<source src="{}"></source></video>'
),
'audio': (
'<audio controls class="audio">'
'<source src="{}"></source></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 (
"<a href='{}'><img class='thumbnail' "
"src='data:image/jpg;base64,{}'></a>"
).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 (
"<a href='{}'><img class='thumbnail' "
"src='data:image/jpg;base64,{}'></a>"
).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 = '<div id="{}">{}<br><span class="filename">{}</span></div>'
elif 'pdf' in mime:
html = '<div id="{}">{}<br><class="filename">{}</span></div>'
else:
html = '<div id="{}">{}</div>'
if 'image' in mime:
html = '<div class="{}">{}<br><span class="filename">{}</span></div>'
elif 'pdf' in mime:
html = '<div class="{}">{}<br><class="filename">{}</span></div>'
else:
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
for root, dirs, files in os.walk(directory):
html = []
for root, dirs, files in os.walk(directory):
html = []
if args.verbose:
print('Listing', root)
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
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 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 = "<pre>"+open(full_path).read()+"</pre>"
else:
a = FILE_TYPES[mime]
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 = "<pre>"+open(full_path).read()+"</pre>"
else:
a = FILE_TYPES[mime]
if mime == 'image' and args.thumbnail:
a = thumbnail(full_path, name)
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 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 = "<a href='{}'>{}</a>"
if args.verbose:
message = 'mime-type not in list, adding as href: \n'
print(message, mime, format, name)
if mime not in FILE_TYPES and format not in FILE_TYPES:
# catch exceptions not defined in FILE_TYPES before
a = "<a href='{}'>{}</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))
a = a.replace('{}', name)
html.append(div(mime, a, name))
if root != directory:
html.append('<a href="../">../</a>')
if root != directory:
html.append('<a class="back" href="../">../</a>')
position = '../' * root.count('/')
stylesheet = '<link type="text/css" rel="stylesheet" href="{}stylesheet.css" />'.format(position)
else:
stylesheet = '<link type="text/css" rel="stylesheet" href="stylesheet.css" />'.format(directory)
for name in dirs:
a = "<a href='{}' class='dir'>{}/</a>".replace('{}', name)
html.append(div('dir', a, 'folder'))
for name in dirs:
a = "<a href='{}' class='dir'>{}/</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)
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')
for line in html:
f.write(line+'\n')
if not args.no_template:
f.write(html_footer)
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)

View File

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