distribusi-foh000/distribusi/distribusi/distribusi.py

424 lines
16 KiB
Python
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
import base64
import os
import subprocess
import re
from urllib.parse import quote
from io import BytesIO
import magic
from PIL import Image, ExifTags
import markdown
from distribusi.page_template import html_footer, html_head
from distribusi.page_template_event import html_footer_event, html_head_event
from distribusi.mappings import CODE_TYPES, FILE_TYPES, SUB_TYPES
from distribusi import fragments
import uuid
from distribusi.ignore import Ignore
MIME_TYPE = magic.Magic(mime=True)
ignore = Ignore()
PATTERN_TAG = re.compile(r"(?P<name>.+?)(?P<tags>\#.+)*\.(?P<ext>.{1,4}$)")
PATTERN_TAG_FOLDER = re.compile(r"(?P<name>.+?)(?P<tags>\#.+)\/(?P<file>.+)")
def untag(name):
m = PATTERN_TAG.search(name)
if m:
file_name = m.group('name')
file_ext = m.group('ext')
return (file_name + "." + file_ext)
else:
return name
def caption(image):
try:
process = subprocess.Popen(
['exiftool', '-Comment', image], stdout=subprocess.PIPE)
out, err = process.communicate()
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:
caption = ''
print(e)
return caption
def thumbnail(image, name, args):
try:
size = (450, 450)
im = Image.open(image)
exif = None
try:
for orientation in ExifTags.TAGS.keys():
if ExifTags.TAGS[orientation] == 'Orientation':
break
exif = im._getexif()
except (AttributeError, KeyError, IndexError):
pass
im.thumbnail(size)
if exif is not None:
if exif[orientation] == 3:
im = im.rotate(180, expand=True)
elif exif[orientation] == 6:
im = im.rotate(270, expand=True)
elif exif[orientation] == 8:
im = im.rotate(90, expand=True)
if (im.mode == 'RGBA'):
bg = Image.new('RGBA', im.size, (255,255,255))
composite = Image.alpha_composite(bg, im)
im=composite.convert('RGB')
output = BytesIO()
im.save(output, format='JPEG')
im_data = output.getvalue()
data_url = base64.b64encode(im_data).decode()
if args.captions:
cap = caption(image)
else:
cap = untag(name)
m = PATTERN_TAG_FOLDER.search(cap)
if m:
folder_name = m.group('name')
file_name = m.group('file')
cap = folder_name + "/" + file_name
return (
"<figure><a href='{}'><img class='thumbnail' src='data:image/jpg;base64,{}'></a><figcaption>{}</figcaption></figure>"
).format(quote(name), data_url, cap)
except Exception as e:
print('Thumbnailer:', e)
cap = name
m = PATTERN_TAG_FOLDER.search(cap)
if m:
folder_name = m.group('name')
file_name = m.group('file')
cap = folder_name + "/" + file_name
return "<figure><a href='{}'><img src='{}'></a><figcaption>{}</figcaption></figure>".format(quote(name), name, cap)
def div(args, type_, subtype, tag, name, fid):
'''
fid: fragment_id
'''
name = untag(name)
if args.no_filenames:
filename = ''
else:
filename = '<span class="filename">{}</span>'.format(name)
if len(str(fid)) >= 36 or int(fid) < 0: # detect if fid is uuid
if 'image' in type_:
html = '<div class="{}">{}</div>'
elif 'pdf' in subtype:
html = '<div class="{}">{}' + filename + '</div>'
elif 'dir' in type_ or 'html' in subtype or 'unkown-file' in subtype:
html = '<div class="{}">{}</div>'
else:
html = '<div class="{}">{}' + filename + '</div>'
html = html.format(subtype, tag)
else:
if 'image' in type_:
html = '<div class="{}"><a class="anchor" id="{}"></a>{}<span class="fid">#{}</span></div>'
elif 'pdf' in subtype:
html = '<div class="{}"><a class="anchor" id="{}"></a>{}' + filename + '<span class="fid">#{}</span></div>'
elif 'dir' in type_ or 'html' in subtype or 'unkown-file' in subtype:
html = '<div class="{}"><a class="anchor" id="{}"></a>{}<span class="fid">#{}</span></div>'
else:
html = '<div class="{}"><a class="anchor" id="{}"></a>{}' + filename + '<span class="fid">#{}</span></div>'
html = html.format(subtype, fid, tag, fid)
return html
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
else:
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
else:
styled_html_head = html_head % ''
print("---")
f.write(styled_html_head)
for line in html:
f.write(line + '\n')
if not args.no_template:
f.write(html_footer)
def render_dir(args, directory):
html = []
print(directory)
for root, dirs, files in os.walk(directory):
for name in sorted(files):
lv = root.split("/")
relative = lv[len(lv) - 1]
relative_path = "./{}/{}".format(relative, name)
if ignore.test(name):
pass
elif '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('/')
cap = untag(name)
if args.verbose:
print('Found file in dir ', name, 'as', mime)
if type_ in FILE_TYPES:
a = FILE_TYPES[type_].format(quote(relative_path), cap, cap)
# 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 = "<div>" + open(full_path).read() + "</div>"
elif subtype == 'markdown' or name.endswith('.md'):
a = "<div>" + markdown.markdown(open(full_path).read()) + "</div>"
pass
else:
subtype = subtype + ' unkown-file'
a = "<a href='{}'>{}</a>"
# a = FILE_TYPES[type_]
if type_ == 'image':
a = FILE_TYPES[type_].format(quote(relative_path), cap, cap)
if args.thumbnail:
a = thumbnail(full_path, relative_path, args)
if args.no_filenames:
cap = ""
if args.captions:
cap = untag(caption(relative_path))
a = FILE_TYPES[type_].format(quote(relative_path), cap, cap)
# ALT 처리
src = os.path.splitext(full_path)
alt_path = src[0] + ".alt"
if os.path.isfile(alt_path):
f = open(alt_path, 'r', encoding='utf-8')
alt = ''
while True:
line = f.readline()
if not line: break
alt = alt + line + ' '
a = FILE_TYPES[type_].format(quote(relative_path), alt, cap)
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('{}', relative_path)
id = uuid.uuid1()
html.append(div(args, type_, subtype, a, name, id))
result = ""
for line in html:
result += line + "\n"
return result
def distribusify(args, directory, freg): # noqa
for root, dirs, files in os.walk(directory):
ignore.add(root)
if ignore.testRoot(root):
continue
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))
dirs.sort()
files.sort()
#
# fragments index
# 작가 폴더 내인 경우 아티스트명 저장
#
artist = None
path = root.split('/')
if len(path) > 2:
artist = path[2].strip()
print(path)
print(artist)
if not args.remove_index:
html = []
if args.verbose:
print('Generating directory listing for', root)
for name in sorted(files):
if ignore.test(name):
print("Ignore : " + name)
elif 'index.html' not in name:
full_path = os.path.join(root, name)
#unfold all the symlinks, too
full_path = os.path.realpath(full_path)
mime = MIME_TYPE.from_file(full_path)
# example: MIME plain/text becomes 'type' plain 'subtype' text
type_, subtype = mime.split('/')
cap = untag(name)
if args.verbose:
print('Found', name, 'as', mime)
if type_ in FILE_TYPES:
a = FILE_TYPES[type_].format(quote(name), cap, cap)
# 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 = "<div>" + open(full_path).read() + "</div>"
elif subtype == 'markdown' or name.endswith('.md'):
a = "<div>" + markdown.markdown(open(full_path).read()) + "</div>"
pass
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:
cap = ""
if args.captions:
cap = untag(caption(full_path))
a = FILE_TYPES[type_].format(quote(name), cap, cap)
# ALT 처리
src = os.path.splitext(full_path)
alt_path = src[0] + ".alt"
if os.path.isfile(alt_path):
f = open(alt_path, 'r', encoding='utf-8')
alt = ''
while True:
line = f.readline()
if not line: break
alt = alt + line + ' '
print("alt: " + alt )
a = FILE_TYPES[type_].format(quote(name), alt, cap)
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)
if (len(path) == 3 and artist) or (len(path) == 4 and artist == "events"):
fid = freg.get_index(artist, name)
html.append(div(args, type_, subtype, a, name, fid))
if root != directory:
if args.menu_with_index:
html.append('<a href="../index.html">../</a>')
else:
html.append('<a href="../">../</a>')
for name in dirs:
if ignore.test(name):
pass
elif (len(path) == 3 and artist) or (len(path) == 4 and artist == "events"):
# dirs 내부의 콘텐츠를 렌더링해 가져와야 함
fid = freg.get_index(artist, name)
rd = render_dir(args, "{}/{}".format(root, name))
# h = '<div id="{}">\n{}</div>'
h = '<div class="folder"><a class="anchor" id="{}"></a>\n{}<span class="fid">#{}</span></div>'.format(fid, rd, fid)
html.append(h)
if not directory == root:
index = os.path.join(root, 'index.html')
if os.path.exists(index):
if check_distribusi_index(args, index):
if artist == "events":
write_index(args, index, html, html_head_event, html_footer_event)
else:
write_index(args, index, html, html_head, html_footer)
elif not os.path.exists(index):
if artist == "events":
write_index(args, index, html, html_head_event, html_footer_event)
else:
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)