adding a version of distribusi that work with a stylesheet file to edit the style of the index pages
This commit is contained in:
parent
870aa07839
commit
d34cd6ec93
98
distribusi/README.md
Normal file
98
distribusi/README.md
Normal 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
|
||||
```
|
@ -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()
|
@ -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)
|
||||
|
@ -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;
|
||||
}
|
||||
"""
|
Loading…
Reference in New Issue
Block a user