Distribusi is a content management system for the web that produces static pages based on the file system.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

219 lines
7.8 KiB

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
MIME_TYPE = magic.Magic(mime=True)
def caption(image):
process = subprocess.Popen(
['exiftool', '-Comment', image], stdout=subprocess.PIPE)
out, err = process.communicate()
except Exception as e:
print('Do you have exiftool installed?')
caption = out.decode("utf-8").split(": ", 1)[1]
except Exception as e:
caption = ''
return caption
def thumbnail(image, name, args):
size = (450, 450)
im = Image.open(image)
if (im.mode == 'RGBA'):
bg = Image.new('RGBA', im.size, (255,255,255))
composite = Image.alpha_composite(bg, im)
output = BytesIO()
im.save(output, format='JPEG')
im_data = output.getvalue()
data_url = base64.b64encode(im_data).decode()
if args.captions:
cap = caption(image)
cap = name
return (
"<figure><a href='{}'><img class='thumbnail' src='data:image/jpg;base64,{}'></a><figcaption>{}</figcaption></figure>"
).format(name, data_url, cap)
except Exception as e:
print('Thumbnailer:', e)
return "<figure><a href='{}'><img src='{}'></a><figcaption>{}</figcaption></figure>".format(name, name, name)
def div(args, type_, subtype, tag, name):
id_name = name.split('.')[0].replace(' ', '_')
if args.no_filenames:
filename = ''
filename = '<span class="filename">{}</span>'.format(name)
if 'image' in type_:
html = '<div id="{}" class="{}">{}</div>'
elif 'pdf' in subtype:
html = '<div id="{}" class="{}">{}' + filename + '</div>'
elif 'dir' in type_ or 'html' in subtype or 'unkown-file' in subtype:
html = '<div id="{}" class="{}">{}</div>'
html = '<div id="{}" class="{}">{}' + filename + '</div>'
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 '<meta name="generator" content="distribusi" />' in f.read():
return True
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):
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
styled_html_head = html_head % ''
for line in html:
f.write(line + '\n')
if not args.no_template:
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))
if not args.remove_index:
html = []
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)
# 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 = '<section id="{}">{}</section>'.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 = "<pre>" + open(full_path).read() + "</pre>"
subtype = subtype+' unkown-file'
a = "<a href='{}'>{}</a>"
# a = FILE_TYPES[type_]
if type_ == 'image':
if args.thumbnail:
a = thumbnail(full_path, name, args)
if args.no_filenames:
caption = ""
a = FILE_TYPES[type_].format(name, caption)
if args.captions:
caption = caption(full_path)
a = FILE_TYPES[type_].format(name, caption)
if subtype in SUB_TYPES:
a = 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
a = "<a href='{}'>{}</a>"
if args.verbose:
message = 'not in list of file types, adding as plain href: \n'
print(type_, subtype, message, name)
subtype = subtype + ' unkown-file'
a = a.replace('{}', name)
html.append(div(args, type_, subtype, a, name))
if root != directory:
if args.menu_with_index:
html.append('<a href="../index.html">../</a>')
html.append('<a href="../">../</a>')
for name in dirs:
if args.menu_with_index:
a = "<a href='{}/index.html'>{}</a>".replace('{}', name)
a = "<a href='{}'>{}/</a>".replace('{}', name)
html.insert(0, div(args, 'dir', 'dir', a, 'folder'))
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)
elif not os.path.exists(index):
write_index(args,index,html, html_head, html_footer)
if args.remove_index:
index = os.path.join(root, 'index.html')
if 'index.html' in files:
if check_distribusi_index(args, index):
if args.verbose:
print('Removing index.html from', root)
except Exception as e: