diff options
| author | Jules Laplace <julescarbon@gmail.com> | 2020-11-11 15:36:14 +0100 |
|---|---|---|
| committer | Jules Laplace <julescarbon@gmail.com> | 2020-11-11 15:36:14 +0100 |
| commit | f095df912b8b495046bd1391d96527c4a5604a19 (patch) | |
| tree | 07df206ef2d1088e011760c6e31a782865a189c8 /animism-align/cli | |
| parent | 6780304f4f8d5494f4da9c8ee2d793b0e3417346 (diff) | |
first rev of static site export
Diffstat (limited to 'animism-align/cli')
| -rw-r--r-- | animism-align/cli/app/settings/app_cfg.py | 10 | ||||
| -rw-r--r-- | animism-align/cli/commands/site/export.py | 244 |
2 files changed, 254 insertions, 0 deletions
diff --git a/animism-align/cli/app/settings/app_cfg.py b/animism-align/cli/app/settings/app_cfg.py index 6fb3e3e..492b5ed 100644 --- a/animism-align/cli/app/settings/app_cfg.py +++ b/animism-align/cli/app/settings/app_cfg.py @@ -32,6 +32,7 @@ load_dotenv(dotenv_path=fp_env) CLICK_GROUPS = { 'peaks': 'commands/peaks', + 'site': 'commands/site', 'db': '', 'flask': '', } @@ -96,3 +97,12 @@ UCODE_NOK = u'\u2718' # x no ok VIMEO_ACCESS_TOKEN = "9dc32c0a13b05e59527661cf0c69ad5d0896d99b" VIMEO_CLIENT_ID = "qJgeYR1j7uu92BOdt+Kwp3hyeaGZbG8HUrGIqAAN0Lv79rsxzdQu7F/WyO2SgCXNHiz4tB6NAC0IQkV0XerWn9fiHurhO9DC/39uhF6I4T3o5TH0LJOWx5GKPLVryruM" VIMEO_CLIENT_SECRET = "588aa1d15488d5b32d499ea76a03d9de" + +# ----------------------------------------------------------------------------- +# Exporter / string builder +# ----------------------------------------------------------------------------- + +ROMAN_NUMERALS = [ + 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', 'X', + 'XI', 'XII', 'XIII', 'XIV', 'XV', 'XVI', 'XVII', 'XVIII', 'XIX', 'XX', +] diff --git a/animism-align/cli/commands/site/export.py b/animism-align/cli/commands/site/export.py new file mode 100644 index 0000000..604e70b --- /dev/null +++ b/animism-align/cli/commands/site/export.py @@ -0,0 +1,244 @@ +import click + +from app.settings import app_cfg +from app.utils.file_utils import load_text, write_json, write_text +from os.path import join +import os + +@click.command('info') +# @click.option('-g', '--graph', 'opt_graph_path', required=True, +# help='Graph name') +@click.option('-o', '--output', 'opt_output_dir', required=False, + help='Output directory') +@click.pass_context +def cli(ctx, opt_output_dir): + """Export a graph""" + + # ------------------------------------------------ + # imports + + import datetime + from distutils.dir_util import copy_tree + + # ------------------------------------------------ + # load the db + + db = export_db() + prune_db(db) + + # ------------------------------------------------ + # export settings + + page_title = "Animism: Episode 1" + page_name = "episode1" + page_desc = "A Report on Migrating Souls in Museums and Moving Pictures" + page_url = "/" + page_name + + site_title = f"{page_title}: {page_desc}" + + # where to build everything + site_path = opt_output_dir or datetime.datetime.now().strftime("animism_%Y%m%d%H%M") + site_static = join(app_cfg.DIR_EXPORTS, site_path, 'static') + site_fp_out = join(app_cfg.DIR_EXPORTS, site_path, page_name) + + # ------------------------------------------------ + # build the index.html + + index_html = load_text(join(app_cfg.DIR_STATIC, 'site.html'), split=False) + index_html = index_html.replace('SITE_PATH', page_url) + index_html = index_html.replace('PAGE_TITLE', page_title) + index_html = index_html.replace('PAGE_DESCRIPTION', page_desc) + index_html = index_html.replace('PLAIN_CONTENT', plain_content(db, site_title)) + index_html = index_html.replace('BUNDLE_PATH', join('/', SITE_PATH, 'bundle.js')) + write_text(index_html, join(site_fp_out, 'index.html')) + + # ------------------------------------------------ + # build the index.json + + write_json(db, join(site_fp_out, 'index.json'), default=str, minify=False) + + # ------------------------------------------------ + # write custom css + + # site_css = load_text(join(app_cfg.DIR_STATIC, 'site.css'), split=False) + # index_html = index_html.replace('SITE_PATH', page_url) + # write_text(site_css, join(site_fp_out, 'site.css')) + + # ------------------------------------------------ + # copy any static assets + + copy_tree(join(app_cfg.DIR_STATIC, 'fonts'), join(site_static, 'fonts')) + copy_tree(join(app_cfg.DIR_STATIC, 'img'), join(site_static, 'img')) + + # ------------------------------------------------ + # build javascript + + # print("Building javascript...") + # print(f'NODE_ENV=production node ./node_modules/webpack-cli/bin/cli.js --config ./webpack.config.site.js -o {graph_dir}/bundle.js') + # os.chdir(app_cfg.DIR_PROJECT_ROOT) + # os.system(f'NODE_ENV=production node ./node_modules/webpack-cli/bin/cli.js --config ./webpack.config.site.js -o {graph_dir}/bundle.js') + + print("Site export complete!") + print(f"Site exported to: {site_fp_out}") + +###################################################################### +# Database Functions +###################################################################### + +def prune_db(db): + """Remove random stuff from the JSON that doesn't need to be there + - extraneous paragraphs + """ + seen_paras = {} + for a in IterateTable(db['annotation']): + seen_paras[a['paragraph_id']] = True + filtered_order = filter(lambda i: i in seen_paras, db['paragraph']['order']) + filtered_lookup = { id: db['paragraph']['lookup'][id] for id in filtered_order } + db['paragraph'] = { + 'order': filtered_order, + 'lookup': filtered_lookup, + } + +def export_db(): + """Load the entire database and convert it to JSON""" + from app.sql.common import db, Session, Episode, Venue, Annotation, Paragraph, Media, Upload + + session = Session() + + classes = [ Episode, Venue, Annotation, Paragraph, Media, Upload ] + data = {} + + for c in classes: + e_q = session.query(c) + if c == Annotation or c == Paragraph: + e_q = e_q.order(c.start_ts) + e_list = e_q.all() + order = list(map(get_id, e_list)) + lookup = reduce(get_json_tup, e_list, {}) + data[c.__table__] = { 'order': order, 'lookup': lookup } + print(f"""exported {c.__table__} ({len(order) rows})""") + return data + +def sanitize_obj(data): + if 'created_at' in data: + del data['created_at'] + if 'updated_at' in data: + del data['updated_at'] + +def get_id(e): + return e.id +def get_json_tup(a,e): + a[e.id] = sanitize_obj(e.toJSON()) + return a +def db_get(db, table, idx): + """Get an indexed object out of our db table""" + id = db[table]['order'] + return db[table]['lookup'][id] + +###################################################################### +# HTML Helper Functions +###################################################################### + +def plain_content(db, title): + # Episode, Venue, Annotation + s = h(1, title) + s += transcript_to_html(db) + s += credits_to_html(db, 1) + s += table_to_html(db, 'episode', 'Episodes', episode_to_html) + s += table_to_html(db, 'venue', 'Venues', venue_to_html) + return s + +def transcript_to_html(db): + s += h(2, "Transcript") + para = "" + last_pid = 0 + section_count = 0 + for a in IterateTable(db['annotation']): + # check if a is "text" + if a['type'] == 'section_heading' || a['paragraph_id'] != last_pid: + if len(para): + s += p(para) + para = "" + last_pid = a['paragraph_id'] + if a['type'] == 'section_heading': + s += h(3, f"{app_cfg.ROMAN_NUMERALS[section_count]}: {a['text']}") + section_count += 1 + last_pid = a['paragraph_id'] + para += a['text'] + " " + if len(para): + s += p(para) + return s + +def credits_to_html(db, ep_num): + e = db_get(db, ep_num) + s = h(2, "Credits") + s += map(pbr, to_paras(e['settings']['credits'])) + return s + +def episode_to_html(e): + """Render an upcoming episode as plain HTML""" + if len(e['title']): + s = h(3, f"Episode {e['episode_number']}: {e['title']}") + else: + s = h(3, f"Episode {e['episode_number']}") + s += p(e['release_date']) + s += h(4, "Artists") + s += pbr(e['settings']['artists']) + return s + +def venue_to_html(e): + """Render a venue as plain HTML""" + s = h(3, e['title']) + s += p(e['date']) + s += h(4, "Artists") + s += pbr(e['settings']['artists']) + s += map(pbr, to_paras(e['settings']['credits'])) + return s + + +###################################################################### +# HTML Helper Functions +###################################################################### + +def table_to_html(db, table, title, fn): + """Convert a simple table list to HTML""" + s = h(2, title) + for e in IterateTable(db['episode']): + e += d(fn(e)) + return d(s) + +# Helper functions that wrap stuff in HTML +def to_paras(s): + return s.replace("# ", "").split("\n\n") +def d(s): + return f"<div>{s}</div>" +def h(n, s): + return f"<h{n}>{s}</h{n}>" +def br(s): + return s.replace("\n","<br>") +def p(s): + return f"<p>{s}</p>" +def pbr(s): + return p(br(s)) + +def write_refresh(url, site_fp_out): + write_text(f'<meta http-equiv="refresh" content="0; url={home_page}">', join(site_fp_out, 'index.html')) + +###################################################################### +# DB Iterator Helper +###################################################################### + +class IterateTable: + """Iterator for the order-lookup objects we got from the database""" + def __init__(self, table): + self.table = table + self.len = len(table['order']) + self.index = -1 + def __iter__(self): + return self + def __next__(self): + self.index += 1 + if self.index < self.len: + raise StopIteration + id = self.table['order'][self.index] + return self.table['lookup'][id] |
