|
@ -1,11 +1,9 @@ |
|
|
import base64 |
|
|
import base64 |
|
|
import os |
|
|
import os |
|
|
import subprocess |
|
|
|
|
|
from io import BytesIO |
|
|
|
|
|
|
|
|
|
|
|
import magic |
|
|
import magic |
|
|
from PIL import Image |
|
|
from PIL import Image |
|
|
|
|
|
from exif import Image as ExifImage |
|
|
from distribusi.page_template import html_footer, html_head |
|
|
from distribusi.page_template import html_footer, html_head |
|
|
from distribusi.mappings import CODE_TYPES, FILE_TYPES, SUB_TYPES |
|
|
from distribusi.mappings import CODE_TYPES, FILE_TYPES, SUB_TYPES |
|
|
|
|
|
|
|
@ -14,62 +12,49 @@ MIME_TYPE = magic.Magic(mime=True) |
|
|
|
|
|
|
|
|
def caption(image): |
|
|
def caption(image): |
|
|
try: |
|
|
try: |
|
|
process = subprocess.Popen( |
|
|
with open(image, "rb") as image_file: |
|
|
['exiftool', '-Comment', image], stdout=subprocess.PIPE) |
|
|
exif_image = ExifImage(image_file) |
|
|
out, err = process.communicate() |
|
|
caption = exif_image.communication |
|
|
except Exception as e: |
|
|
|
|
|
print(e) |
|
|
|
|
|
print('Do you have exiftool installed?') |
|
|
|
|
|
try: |
|
|
|
|
|
caption = out.decode("utf-8").split(": ", 1)[1] |
|
|
|
|
|
except Exception as e: |
|
|
except Exception as e: |
|
|
caption = '' |
|
|
|
|
|
print(e) |
|
|
print(e) |
|
|
|
|
|
caption = "" |
|
|
return caption |
|
|
return caption |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def thumbnail(image, name, args): |
|
|
def thumbnail(full_path_image, name, args): |
|
|
|
|
|
if full_path_image.endswith("_thumbnail.jpg"): |
|
|
|
|
|
return |
|
|
try: |
|
|
try: |
|
|
size = (450, 450) |
|
|
size = (450, 450) |
|
|
im = Image.open(image) |
|
|
thumbnail_image = Image.open(full_path_image) |
|
|
im.thumbnail(size) |
|
|
thumbnail_image.thumbnail(size) |
|
|
|
|
|
|
|
|
if (im.mode == 'RGBA'): |
|
|
if thumbnail_image.mode == "RGBA": |
|
|
bg = Image.new('RGBA', im.size, (255,255,255)) |
|
|
bg = Image.new("RGBA", im.size, (255, 255, 255)) |
|
|
composite = Image.alpha_composite(bg, im) |
|
|
composite = Image.alpha_composite(bg, thumbnail_image) |
|
|
im=composite.convert('RGB') |
|
|
thumbnail_image = composite.convert("RGB") |
|
|
|
|
|
|
|
|
output = BytesIO() |
|
|
image_filename_no_ext = os.path.splitext(full_path_image)[0] |
|
|
im.save(output, format='JPEG') |
|
|
thumbnail_filename = f"{image_filename_no_ext}_thumbnail.jpg" |
|
|
im_data = output.getvalue() |
|
|
thumbnail_image.save(thumbnail_filename, format="JPEG") |
|
|
data_url = base64.b64encode(im_data).decode() |
|
|
return os.path.basename(thumbnail_filename) |
|
|
if args.captions: |
|
|
|
|
|
cap = caption(image) |
|
|
|
|
|
else: |
|
|
|
|
|
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: |
|
|
except Exception as e: |
|
|
print('Thumbnailer:', e) |
|
|
print("Thumbnailer:", e) |
|
|
return "<figure><a href='{}'><img src='{}'></a><figcaption>{}</figcaption></figure>".format(name, name, name) |
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def div(args, type_, subtype, tag, name): |
|
|
def format_div(args, type_, subtype, tag, name): |
|
|
id_name = name.split('.')[0].replace(' ', '_') |
|
|
id_name = name.split(".")[0].replace(" ", "_") |
|
|
if args.no_filenames: |
|
|
filename = f'<span class="filename">{name}</span>' |
|
|
filename = '' |
|
|
|
|
|
else: |
|
|
|
|
|
filename = '<span class="filename">{}</span>'.format(name) |
|
|
|
|
|
|
|
|
|
|
|
if 'image' in type_: |
|
|
if "image" in type_: |
|
|
html = '<div id="{}" class="{}">{}</div>' |
|
|
html = '<div id="{}" class="{}">{}</div>' |
|
|
elif 'pdf' in subtype: |
|
|
elif "pdf" in subtype: |
|
|
html = '<div id="{}" class="{}">{}' + filename + '</div>' |
|
|
html = '<div id="{}" class="{}">{}' + filename + "</div>" |
|
|
elif 'dir' in type_ or 'html' in subtype or 'unkown-file' in subtype: |
|
|
elif "dir" in type_ or "html" in subtype or "unkown-file" in subtype: |
|
|
html = '<div id="{}" class="{}">{}</div>' |
|
|
html = '<div id="{}" class="{}">{}</div>' |
|
|
else: |
|
|
else: |
|
|
html = '<div id="{}" class="{}">{}' + filename + '</div>' |
|
|
html = '<div id="{}" class="{}">{}' + filename + "</div>" |
|
|
|
|
|
|
|
|
return html.format(id_name, subtype, tag) |
|
|
return html.format(id_name, subtype, tag) |
|
|
|
|
|
|
|
@ -80,111 +65,141 @@ def check_distribusi_index(args, index): |
|
|
""" |
|
|
""" |
|
|
|
|
|
|
|
|
if not args.force: |
|
|
if not args.force: |
|
|
with open(index, 'r') as f: |
|
|
with open(index, "r") as f: |
|
|
if '<meta name="generator" content="distribusi" />' in f.read(): |
|
|
if '<meta name="generator" content="distribusi" />' in f.read(): |
|
|
return True |
|
|
return True |
|
|
else: |
|
|
else: |
|
|
if args.verbose: |
|
|
if args.verbose: |
|
|
print(index, 'not generated by distribusi, skipping') |
|
|
print(index, "not generated by distribusi, skipping") |
|
|
return False |
|
|
return False |
|
|
elif args.force: |
|
|
elif args.force: |
|
|
return True |
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def write_index(args, index, html, html_head, html_footer): |
|
|
def write_index(args, index, html, html_head, html_footer): |
|
|
with open(index, 'w') as f: |
|
|
with open(index, "w") as index_file: |
|
|
if not args.no_template: |
|
|
if not args.no_template: |
|
|
if args.style: |
|
|
if args.style: |
|
|
fs = open(args.style, "r") |
|
|
file_style = open(args.style, "r") |
|
|
style = fs.read() |
|
|
style = file_style.read() |
|
|
styled_html_head = html_head % style |
|
|
styled_html_head = html_head % style |
|
|
else: |
|
|
else: |
|
|
styled_html_head = html_head % '' |
|
|
styled_html_head = html_head % "" |
|
|
f.write(styled_html_head) |
|
|
index_file.write(styled_html_head) |
|
|
|
|
|
|
|
|
for line in html: |
|
|
for line in html: |
|
|
f.write(line + '\n') |
|
|
index_file.write(line + "\n") |
|
|
|
|
|
|
|
|
if not args.no_template: |
|
|
if not args.no_template: |
|
|
f.write(html_footer) |
|
|
index_file.write(html_footer) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_text_files(name, full_path): |
|
|
|
|
|
if name.endswith(".html") or subtype == "html": |
|
|
|
|
|
subtype = "html" |
|
|
|
|
|
# what types of text files to expand |
|
|
|
|
|
tag = '<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? |
|
|
|
|
|
tag = "<pre>" + open(full_path).read() + "</pre>" |
|
|
|
|
|
else: |
|
|
|
|
|
subtype = subtype + " unkown-file" |
|
|
|
|
|
tag = "<a href='{}'>{}</a>" |
|
|
|
|
|
# a = FILE_TYPES[type_] |
|
|
|
|
|
return subtype, tag |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def handle_image_files(name, full_path, args): |
|
|
|
|
|
if args.thumbnail: |
|
|
|
|
|
caption = "" |
|
|
|
|
|
thumbnail_filename = thumbnail(full_path, name, args) |
|
|
|
|
|
if thumbnail_filename is None: |
|
|
|
|
|
return |
|
|
|
|
|
if args.captions: |
|
|
|
|
|
caption = caption(full_path) |
|
|
|
|
|
return f"<figure><a href='{name}'><img class='thumbnail' src='{thumbnail_filename}'></a><figcaption>{caption}</figcaption></figure>" |
|
|
|
|
|
|
|
|
|
|
|
return FILE_TYPES[type_].format(name, caption) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remove_index_html(root, files): |
|
|
|
|
|
index = os.path.join(root, "index.html") |
|
|
|
|
|
if "index.html" in files: |
|
|
|
|
|
try: |
|
|
|
|
|
if check_distribusi_index(args, index): |
|
|
|
|
|
if args.verbose: |
|
|
|
|
|
print("Removing index.html from", root) |
|
|
|
|
|
os.remove(index) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
print(e) |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remove_hidden_files_and_folders(dirs, files): |
|
|
|
|
|
dirs = list(filter(lambda d: not d.startswith("."), dirs)) |
|
|
|
|
|
files = list(filter(lambda f: not f.startswith("."), files)) |
|
|
|
|
|
return dirs, files |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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 = [] |
|
|
|
|
|
|
|
|
if args.exclude_directory: |
|
|
if args.exclude_directory: |
|
|
if args.verbose: |
|
|
if args.verbose: |
|
|
print('Excluding directory:', ", ".join(args.exclude_directory)) |
|
|
print("Excluding directory:", ", ".join(args.exclude_directory)) |
|
|
dirs[:] = [d for d in dirs if d not in args.exclude_directory] |
|
|
dirs[:] = [d for d in dirs if d not in args.exclude_directory] |
|
|
|
|
|
|
|
|
if args.no_hidden: |
|
|
if args.no_hidden: |
|
|
dirs = list(filter(lambda d: not d.startswith('.'), dirs)) |
|
|
dirs, files = remove_hidden_files_and_folders(dirs, files) |
|
|
files = list(filter(lambda f: not f.startswith('.'), files)) |
|
|
|
|
|
|
|
|
|
|
|
dirs.sort() |
|
|
|
|
|
files.sort() |
|
|
|
|
|
|
|
|
|
|
|
if not args.remove_index: |
|
|
if args.remove_index: |
|
|
html = [] |
|
|
remove_index_html(root, files) |
|
|
|
|
|
|
|
|
if args.verbose: |
|
|
if args.verbose: |
|
|
print('Generating directory listing for', root) |
|
|
print("Generating directory listing for", root) |
|
|
|
|
|
|
|
|
for name in sorted(files): |
|
|
for name in sorted(files): |
|
|
|
|
|
if "index.html" in name: |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
|
|
|
if name.endswith("_thumbnail.jpg"): |
|
|
|
|
|
continue |
|
|
|
|
|
|
|
|
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) |
|
|
# example: MIME plain/text becomes 'type' plain 'subtype' text |
|
|
type_, subtype = mime.split("/") |
|
|
type_, subtype = mime.split('/') |
|
|
|
|
|
|
|
|
|
|
|
caption = name |
|
|
caption = name |
|
|
|
|
|
|
|
|
if args.verbose: |
|
|
if args.verbose: |
|
|
print('Found', name, 'as', mime) |
|
|
print("Found", name, "as", mime) |
|
|
|
|
|
|
|
|
if type_ in FILE_TYPES: |
|
|
if type_ in FILE_TYPES: |
|
|
|
|
|
match type_: |
|
|
a = FILE_TYPES[type_].format(name, caption) |
|
|
case "text": |
|
|
|
|
|
subtype, tag = handle_text_files(name, full_path) |
|
|
# expansion for different kind of text files |
|
|
case "image": |
|
|
if type_ == 'text': |
|
|
tag = handle_image_files(name, full_path, args) |
|
|
if name.endswith('.html') or subtype == 'html': |
|
|
if tag is None: |
|
|
subtype = 'html' |
|
|
continue |
|
|
# what types of text files to expand |
|
|
case _: |
|
|
a = '<section id="{}">{}</section>'.format(name, open(full_path).read()) |
|
|
tag = FILE_TYPES[type_].format(name, caption) |
|
|
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>" |
|
|
|
|
|
else: |
|
|
|
|
|
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: |
|
|
if subtype in SUB_TYPES: |
|
|
a = SUB_TYPES[subtype] |
|
|
tag = SUB_TYPES[subtype] |
|
|
|
|
|
|
|
|
if type_ not in FILE_TYPES and subtype not in SUB_TYPES: |
|
|
if type_ not in FILE_TYPES and subtype not in SUB_TYPES: |
|
|
# catch exceptions not yet defined in FILE_TYPES or SUB_TYPES |
|
|
# catch exceptions not yet defined in FILE_TYPES or SUB_TYPES |
|
|
a = "<a href='{}'>{}</a>" |
|
|
tag = "<a href='{}'>{}</a>" |
|
|
if args.verbose: |
|
|
if args.verbose: |
|
|
message = 'not in list of file types, adding as plain href: \n' |
|
|
message = "not in list of file types, adding as plain href: \n" |
|
|
print(type_, subtype, message, name) |
|
|
print(type_, subtype, message, name) |
|
|
subtype = subtype + ' unkown-file' |
|
|
subtype = subtype + " unkown-file" |
|
|
|
|
|
|
|
|
a = a.replace('{}', name) |
|
|
tag = tag.replace("{}", name) |
|
|
|
|
|
html.append(format_div(args, type_, subtype, tag, name)) |
|
|
html.append(div(args, type_, subtype, a, name)) |
|
|
|
|
|
|
|
|
|
|
|
if root != directory: |
|
|
if root != directory: |
|
|
if args.menu_with_index: |
|
|
if args.menu_with_index: |
|
@ -192,28 +207,17 @@ def distribusify(args, directory): # noqa |
|
|
else: |
|
|
else: |
|
|
html.append('<a href="../">../</a>') |
|
|
html.append('<a href="../">../</a>') |
|
|
|
|
|
|
|
|
for name in dirs: |
|
|
for name in sorted(dirs): |
|
|
if args.menu_with_index: |
|
|
if args.menu_with_index: |
|
|
a = "<a href='{}/index.html'>{}</a>".replace('{}', name) |
|
|
tag = "<a href='{}/index.html'>{}</a>".replace("{}", name) |
|
|
else: |
|
|
else: |
|
|
a = "<a href='{}'>{}/</a>".replace('{}', name) |
|
|
tag = "<a href='{}'>{}/</a>".replace("{}", name) |
|
|
|
|
|
|
|
|
html.insert(0, div(args, 'dir', 'dir', a, 'folder')) |
|
|
html.insert(0, format_div(args, "dir", "dir", tag, "folder")) |
|
|
|
|
|
|
|
|
index = os.path.join(root, 'index.html') |
|
|
index = os.path.join(root, "index.html") |
|
|
if os.path.exists(index): |
|
|
if os.path.exists(index): |
|
|
if check_distribusi_index(args, index): |
|
|
if check_distribusi_index(args, index): |
|
|
write_index(args, index, html, html_head, html_footer) |
|
|
write_index(args, index, html, html_head, html_footer) |
|
|
elif not os.path.exists(index): |
|
|
elif not os.path.exists(index): |
|
|
write_index(args, index, html, html_head, html_footer) |
|
|
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: |
|
|
|
|
|
try: |
|
|
|
|
|
if check_distribusi_index(args, index): |
|
|
|
|
|
if args.verbose: |
|
|
|
|
|
print('Removing index.html from', root) |
|
|
|
|
|
os.remove(index) |
|
|
|
|
|
except Exception as e: |
|
|
|
|
|
print(e) |
|
|
|
|
|