summaryrefslogtreecommitdiff
path: root/animism-align/cli
diff options
context:
space:
mode:
Diffstat (limited to 'animism-align/cli')
-rw-r--r--animism-align/cli/app/settings/app_cfg.py10
-rw-r--r--animism-align/cli/commands/site/export.py244
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]