imaginary-realities/gensite.py

742 lines
32 KiB
Python

# CURRENT:
# TODO: Shared
# TODO: generate TARGET_EBOOK
# TODO: Send HTML & CSS to ebook format converter:
# TODO: pdf generation
# - Both mobi and pdf generation are done via Qt. Calibre is linked against glibc 3.13,
# and the shared hosting has an older version. So Calibre can't find parts of Qt.
# TODO: generate TARGET_WEBSITE
# TODO: Script invocation needs to be more flexible.
# - It should be possible to regenerate one file.
# - the home page, with discuss comments.
# TODO: The update script should poll disqus and get the relevant data.
# - the home page, with featured article changing periodically (random selection from valid candidates with right data).
# TODO: Go through articles and add featured status elements.
# TODO: Have some sort of database with last update status, which an update script hits.
# - any article page, with linked resources being updated as needed.
# TODO: Reddit posts and comments.
# TODO: Disqus comments are now added to all issue articles in the website.
# Could add comment counts to page titles or to links to issue articles:
# https://help.disqus.com/customer/portal/articles/565624-tightening-your-disqus-integration
# Where else to add disqus comments?
# - Other issue pages than articles?
# - Home page?
# - Contribute page? Other pages?
# TODO: RSS feed may need to include announcements.
# - add from text file.
# - edit in text file.
#
import calendar
import codecs
import distutils
import distutils.dir_util # Not needed on windows.
import distutils.file_util # Not needed on windows.
import email.utils
import json
import os
import shutil
import subprocess
import sys
import time
import jinja2
import feedformatter
FLAG_ONLINE = 1 << 31
TARGET_EBOOK = 1
TARGET_WEBSITE = 2
# This defines where to look for the base template for a given target.
templates_by_target = {
TARGET_EBOOK: os.path.join("templates", "ebook"),
TARGET_WEBSITE | FLAG_ONLINE: os.path.join("templates", "website"),
TARGET_WEBSITE: os.path.join("templates", "website"),
}
""" Variable to configure for generation of final result with side-effects. """
setting_finalise = True
setting_domain_name = "journal.imaginary-realities.com"
PAGE_OTHER = 1
PAGE_ARTICLE = 2
issue_data = {
# (volume_number, issue_number, (year, month))
(5,1,(2013,12)): [
(PAGE_OTHER, "introduction"),
(PAGE_OTHER, "copyright"),
(PAGE_ARTICLE, "modern-interface-modern-mud"),
(PAGE_ARTICLE, "well-built-zone-work-art"),
(PAGE_ARTICLE, "journey-through-paradice"),
(PAGE_ARTICLE, "blind-accessibility-challenges-opportunities"),
(PAGE_ARTICLE, "evennia-introduction"),
(PAGE_ARTICLE, "getting-roleplaying-scene-going"),
(PAGE_ARTICLE, "introducing-new-players-redesigning-mud-school"),
(PAGE_ARTICLE, "hunger-game-learned-break-ship-bottle"),
(PAGE_ARTICLE, "help-save-old-mudding-resources"),
(PAGE_OTHER, "request-for-content"),
(PAGE_OTHER, "staff"),
],
(6,1,(2014,4)): [
(PAGE_OTHER, "introduction"),
(PAGE_OTHER, "copyright"),
(PAGE_ARTICLE, "a-journey-through-paradice-ii"),
(PAGE_ARTICLE, "building-a-mech-in-evennia"),
(PAGE_ARTICLE, "describing-a-virtual-world"),
(PAGE_ARTICLE, "dynamic-room-descriptions"),
(PAGE_ARTICLE, "saddle-up"),
(PAGE_ARTICLE, "the-successful-quest-builder"),
(PAGE_ARTICLE, "your-mud-should-have-an-account-system"),
(PAGE_ARTICLE, "help-save-old-mudding-resources"),
(PAGE_OTHER, "request-for-content"),
(PAGE_OTHER, "staff"),
],
(7,1,(2015,1)): [
(PAGE_OTHER, "introduction"),
(PAGE_OTHER, "copyright"),
(PAGE_ARTICLE, "choosing-an-emoting-system"),
(PAGE_ARTICLE, "dungeon-keeper"),
(PAGE_ARTICLE, "what-i-do-now"),
(PAGE_ARTICLE, "worlds-in-which-we-wander"),
(PAGE_OTHER, "request-for-content"),
(PAGE_OTHER, "staff"),
],
(7,2,(2015,4)): [
(PAGE_OTHER, "introduction"),
(PAGE_OTHER, "copyright"),
(PAGE_ARTICLE, "bartering"),
(PAGE_ARTICLE, "is-structuralism-a-viable-critical-lens-for-roguelike-games"),
(PAGE_OTHER, "request-for-content"),
(PAGE_OTHER, "staff"),
],
(7,3,(2015,7)): [
(PAGE_OTHER, "introduction"),
(PAGE_OTHER, "copyright"),
(PAGE_ARTICLE, "a-text-mud-with-a-working-ecology-system"),
(PAGE_ARTICLE, "dispelling-the-gloom"),
(PAGE_ARTICLE, "how-integral-are-letters-and-text-to-ascii-gaming"),
(PAGE_ARTICLE, "legend-and-the-lore"),
(PAGE_ARTICLE, "the-bonds-of-mudding"),
(PAGE_ARTICLE, "the-mercurial-temperament-at-the-end-of-the-world"),
(PAGE_ARTICLE, "where-do-i-begin"),
(PAGE_OTHER, "request-for-content"),
(PAGE_OTHER, "staff"),
]
}
class TemplateParameters(object):
pass
def init_template_data(tp):
tp.key = None
tp.full_url = tp.page_permanent_id.replace("website/", "http://"+ setting_domain_name +"/")
tp.target_is_online = (setting_generation_target & FLAG_ONLINE) == FLAG_ONLINE
tp.target_is_website = (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE
tp.sections = TemplateParameters()
if not hasattr(tp, "link_prefix"):
tp.link_prefix = ""
if (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE:
tp.homepage_link = tp.link_prefix +"index.html"
tp.contact_link = tp.link_prefix +"contact.html"
tp.copyright_link = tp.link_prefix +"copyright.html"
tp.contribute_link = tp.link_prefix +"contribute.html"
tp.links_link = tp.link_prefix +"links.html"
else:
tp.contribute_link = tp.link_prefix +"request-for-content/index.html"
tp.rss_link = "http://"+ setting_domain_name +"/feed_rss2.xml"
tp.twitter_link = "https://twitter.com/irjrnl"
tp.reddit_link = "http://www.reddit.com/r/imaginaryrealities/"
if (setting_generation_target & FLAG_ONLINE) == FLAG_ONLINE:
tp.js_jquery_link = "http://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"
else:
if setting_use_minimised_files:
tp.js_jquery_link = tp.link_prefix +"js/jquery-1.11.3.min.js"
else:
tp.js_jquery_link = tp.link_prefix +"js/jquery-1.11.3.js"
tp.license_text = "CC BY SA NC"
tp.license_link = "http://creativecommons.org/licenses/by-nc-sa/3.0/nz/"
tp.website_title_text = "Imaginary Realities"
tp.menu = TemplateParameters()
tp.menu.back_issues_title = "Back Issues"
tp.menu.latest_issue_title = "Current Issue"
get_latest_issue_data(tp)
get_back_issues_data(tp)
def get_latest_issue_data(tp):
tp.sections.latest_issue = TemplateParameters()
tp.sections.latest_issue.title = "Latest Issue"
tp.sections.latest_issue.issue_articles = []
issue_keys = issue_data.keys()
issue_keys.sort(lambda a, b: cmp(b, a))
issue_key = issue_keys[0]
volume_number, issue_number, (year_number, month_number) = issue_key
issue_link = "volume-%02d/issue-%02d/" % (volume_number, issue_number)
tp.sections.latest_issue.issue_title = "Volume %d, Issue %d (%s %d)" % (volume_number, issue_number, calendar.month_name[month_number], year_number)
for article_type, page_dirname in issue_data[issue_key]:
if page_dirname in setting_website_hidden_issue_pages: continue
article = TemplateParameters()
article.title = get_article_block_content(volume_number, issue_number, page_dirname, "page_title")
article.link = issue_link + page_dirname +"/index.html"
tp.sections.latest_issue.issue_articles.append(article)
tp.sections.latest_issue.read_text = "Read this issue"
tp.sections.latest_issue.read_link = issue_link +"index.html"
def get_back_issues_data(tp):
tp.sections.back_issues = TemplateParameters()
tp.sections.back_issues.title = "Back Issues"
tp.sections.back_issues.issues = []
issue_keys = issue_data.keys()
issue_keys.sort(lambda a, b: cmp(b, a))
for issue_key in issue_keys[1:]:
volume_number, issue_number, (year_number, month_number) = issue_key
issue = TemplateParameters()
issue.link = "volume-%02d/issue-%02d/index.html" % (volume_number, issue_number)
issue.volume_text = "Volume %d, Issue %d" % (volume_number, issue_number)
issue.publication_year_text = "%s %d" % (calendar.month_name[month_number], year_number)
tp.sections.back_issues.issues.append(issue)
def generate_website_index_page():
global data_disqus
t = jinja2_env.get_template("homepage.html")
output_path = os.path.join(setting_target_dirname, "index.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
init_template_data(tp)
tp.key = "website_index"
tp.sections.introduction = TemplateParameters()
tp.sections.featured_article = TemplateParameters()
tp.sections.recent_comments = TemplateParameters()
# SECTION: Introduction
tp.sections.introduction.logo_text = "An old logo for Imaginary Realities, with a lower-case i beside a upper-case R"
tp.sections.introduction.logo_link = "images/logo.png"
# SECTION: Featured article
tp.sections.featured_article.title = "Featured Article"
featured_article_key = (7,1,"what-i-do-now")
volume_number, issue_number, page_dirname = featured_article_key
article_title = get_article_block_content(volume_number, issue_number, page_dirname, "page_title")
article_link = "volume-%02d/issue-%02d/%s/index.html" % (volume_number, issue_number, page_dirname)
article_authors = get_article_block_content(volume_number, issue_number, page_dirname, "article_authors")
feature_excerpt = get_article_block_content(volume_number, issue_number, page_dirname, "feature_excerpt")
feature_hype = get_article_block_content(volume_number, issue_number, page_dirname, "feature_hype")
tp.sections.featured_article.article_title = article_title
tp.sections.featured_article.article_hype_text = feature_hype
tp.sections.featured_article.article_quote_text = feature_excerpt
tp.sections.featured_article.article_authorname_text = article_authors
tp.sections.featured_article.read_text = "Read this article"
tp.sections.featured_article.read_link = article_link
# SECTION: Recent comments
tp.sections.recent_comments.title = "Recent Comments"
tp.sections.recent_comments.entries = []
tp.sections.recent_comments.is_enabled = True
if data_disqus is None:
tp.sections.recent_comments.is_enabled = False
tp.sections.recent_comments.content = """<div class="watch-this-space">Failed to generate content.</div>"""
else:
# comment.comment_id/user_name/timestamp/thread_id/text
for comment in data_disqus.get_recent_comments():
# thread.url/feed/title
thread = data_disqus.get_thread(comment.thread_id)
text = comment.text
while " " in text:
text = text.replace(" ", " ")
text = text[:80]+"..."
entry = TemplateParameters()
entry.age_string = data_disqus.get_time_string(comment.timestamp)
entry.user_name = comment.user_name
entry.thread_title = thread.title
entry.thread_url = thread.url
entry.text = text
tp.sections.recent_comments.entries.append(entry)
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_website_contact_page():
t = jinja2_env.get_template("contact.html")
output_path = os.path.join(setting_target_dirname, "contact.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
init_template_data(tp)
tp.key = "website_contact"
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_website_links_page():
t = jinja2_env.get_template("links.html")
output_path = os.path.join(setting_target_dirname, "links.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
init_template_data(tp)
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_website_copyright_page():
t = jinja2_env.get_template("copyright.html")
output_path = os.path.join(setting_target_dirname, "copyright.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
init_template_data(tp)
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_website_contribute_page():
t = jinja2_env.get_template("contribute.html")
output_path = os.path.join(setting_target_dirname, "contribute.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
init_template_data(tp)
tp.key = "website_contribute"
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_website_rss():
feed = feedformatter.Feed()
feed.feed["title"] = "Imaginary Realities"
feed.feed["link"] = "http://"+ setting_domain_name +"/"
feed.feed["author"] = "Richard Tew"
feed.feed["description"] = "Announcements related to the Imaginary Realities publication"
# Load in existing items, in order of oldest to newest.
feed_items = json.load(open("feed.json", "rb"))
changes_made = False
existing_links = []
for feed_item in feed_items:
if type(feed_item["pubDate"]) in (str, unicode): # RFC2822
d = email.utils.parsedate_tz(feed_item["pubDate"])
feed_item["pubDate"] = email.utils.mktime_tz(d) # Seconds since epoch.
changes_made = True
feed.items.append(feed_item)
link = feed_item["link"]
if link.endswith("/"):
link += "index.html"
existing_links.append(link)
# Add missing issues in order of publication (which is how the feed goes).
issue_keys = issue_data.keys()
issue_keys.sort()
for issue_key in issue_keys:
volume_number, issue_number, (year_number, month_number) = issue_key
missing_link = feed.feed["link"] + "volume-%02d/issue-%02d/index.html" % (volume_number, issue_number)
download_link = feed.feed["link"] + "files/"
if missing_link not in existing_links:
print "RSS: Adding issue to feed, volume %d, issue %d" % (volume_number, issue_number)
item = {}
item["title"] = "Imaginary Realities - Volume %d, Issue %d" % (volume_number, issue_number)
item["description"] = "<p>Our latest issue as of %s %d. Long delayed, but finally here. Read it <a href='%s'>online</a>, or <a href='%s'>download it</a> as an epub e-book or PDF document. Follow <a href='https://twitter.com/intent/user?screen_name=irjrnl'>our twitter</a>, if that's your thing. Imaginary Realities contains articles related to mudding, and other text-based forms of gaming include interactive fiction and roguelikes.</p>" % (calendar.month_name[month_number], year_number, missing_link, download_link)
item["link"] = missing_link
item["pubDate"] = time.time()
item["guid"] = "%d" % (time.time() * 100)
feed_items.append(item)
feed.items.append(item)
changes_made = True
if setting_finalise:
if changes_made:
# Update the json record of what has already been published (to try and avoid sending all entries out again, everytime we add a new RSS entry.
json.dump(feed_items, open("feed.json", "wb"))
print "RSS feed store modified, changes made."
else:
print "RSS feed store not modified, no changes to make."
else:
print "WARNING: Results are not finalised, published result should be finalised."
# Generate the RSS2 feed.
feed.format_rss2_file(os.path.join(setting_target_dirname, "feed_rss2.xml"))
### ISSUE GENERATION
def generate_website():
print "Generating website"
generate_website_index_page()
generate_website_contact_page()
generate_website_copyright_page()
generate_website_contribute_page()
# generate_website_links_page()
generate_website_rss()
if (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE:
for dirname in ("css", "js", "fonts", "images"):
distutils.dir_util.copy_tree(os.path.join("templates", "website", dirname), os.path.join(setting_target_dirname, dirname))
def generate_issue_page(issue_nav, volume_number, issue_number, year_number, month_number, page_type, page_dirname):
outputdir_path = os.path.join(setting_target_dirname, "volume-%02d" % volume_number, "issue-%02d" % issue_number, page_dirname)
inputdir_path = os.path.join("templates", "volume%02d_issue%02d" % (volume_number, issue_number), page_dirname)
inputtemplate_name = "index.html"
shutil.copytree(inputdir_path, outputdir_path, ignore=shutil.ignore_patterns(inputtemplate_name))
jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader([ "templates", setting_base_template, inputdir_path ]))
t = jinja2_env.get_template(inputtemplate_name)
output_path = os.path.join(outputdir_path, "index.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
# TODO: Path should be set more intelligently. Perhaps absolute in some cases.
if (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE:
# Full scope is [TOP/VOLUME/ISSUE/PAGE.html], so 3 levels moves from PAGE to TOP.
tp.link_prefix = "../../../"
else:
# Full scope is [ISSUE/PAGE.html], so 1 levels moves from PAGE to ISSUE.
tp.link_prefix = "../"
init_template_data(tp)
tp.volume_number = volume_number
tp.issue_number = issue_number
tp.issue_link = "../index.html"
tp.issue_nav = issue_nav
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_issue_toc(issue_nav, issue_metadata, issue_pagedata):
volume_number, issue_number, (year_number, month_number) = issue_metadata
inputdir_path = os.path.join("templates", "issue")
outputdir_path = os.path.join(setting_target_dirname, "volume-%02d" % volume_number, "issue-%02d" % issue_number)
jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader([ "templates", setting_base_template, inputdir_path ]))
t = jinja2_env.get_template("toc.html")
output_path = os.path.join(outputdir_path, "index.html")
tp = TemplateParameters()
tp.page_permanent_id = output_path.replace("\\", "/")
# TODO: Path should be set more intelligently. Perhaps absolute in some cases.
if (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE:
# Full scope is [TOP/VOLUME/ISSUE/<HERE>/PAGE], so 2 levels moves from PAGE to TOP.
tp.link_prefix = "../../"
else:
# Full scope is [<HERE>/PAGE], so 0 levels moves to ISSUE.
tp.link_prefix = ""
init_template_data(tp)
tp.volume_number = volume_number
tp.issue_number = issue_number
tp.issue_link = "index.html"
tp.logo_text = "An old logo for Imaginary Realities, with a lower-case i beside a upper-case R"
tp.logo_link = "images/logo.png"
tp.page_title = "Table of Contents"
tp.issue = TemplateParameters()
tp.issue.articles = []
for page_type, page_dirname in issue_pagedata:
if page_dirname in setting_website_hidden_issue_pages: continue
article = TemplateParameters()
article.title = get_article_block_content(volume_number, issue_number, page_dirname, "page_title")
article.author_names = get_article_block_content(volume_number, issue_number, page_dirname, "article_authors").replace(" and ", "<br/>")
article.link = page_dirname +"/index.html"
tp.issue.articles.append(article)
tp.issue.read_link = issue_pagedata[0][1] +"/index.html"
tp.issue.read_text = "Read on.."
tp.issue_nav = issue_nav
html = t.render(tp=tp)
with codecs.open(output_path, "wb", "utf-8") as f:
f.write(html)
def generate_issues(issue_data):
issue_metadatas = issue_data.keys()
issue_metadatas.sort()
last_issue_index = len(issue_metadatas)-1
for issue_index, issue_metadata in enumerate(issue_metadatas):
issue_pagedata = issue_data[issue_metadata]
volume_number, issue_number, (year_number, month_number) = issue_metadata
print "Generating issue volume %d, issue %d" % (volume_number, issue_number)
volume_path = os.path.join(setting_target_dirname, "volume-%02d" % volume_number)
issue_path = os.path.join(volume_path, "issue-%02d" % issue_number)
distutils.dir_util.mkpath(issue_path)
images_input_path = os.path.join("templates", "volume%02d_issue%02d" % (volume_number, issue_number), "images")
if os.path.exists(images_input_path):
images_output_path = os.path.join(issue_path, "images")
distutils.dir_util.copy_tree(images_input_path, images_output_path)
# Copy a set of the dependent files to each issue, for local use.
if (setting_generation_target & TARGET_EBOOK) == TARGET_EBOOK:
for parent_template_name in [ "website", "ebook" ]:
parent_template_path = os.path.join("templates", parent_template_name)
for entry_name in os.listdir(parent_template_path):
entry_path = os.path.join(parent_template_path, entry_name)
if os.path.isdir(entry_path):
if parent_template_name == "website" and entry_name == "images":
# There are a lot of images we do not need.
for file_name in [ "logo.png" ]:
dest_path = os.path.join(issue_path, entry_name)
distutils.dir_util.mkpath(dest_path)
distutils.file_util.copy_file(os.path.join(entry_path, file_name), os.path.join(dest_path, file_name))
else:
distutils.dir_util.copy_tree(entry_path, os.path.join(issue_path, entry_name))
# TODO: The whole issue_nav debacle should be skipped for non-website builds.
# TODO: Non-website builds should not have issue_nav
if (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE:
issue_nav = TemplateParameters()
else:
issue_nav = None
if issue_nav:
# Inter-article navigation button priming (setup done on per-article basis below).
default_prev_article_html = issue_nav.prev_article_html = "&#x00AB; article"
issue_nav.prev_article_class = ""
default_next_article_html = issue_nav.next_article_html = "article &#x00BB;"
issue_nav.next_article_class = ""
# Inter-issue navigation button setup.
default_prev_issue_html = issue_nav.prev_issue_html = "&#x00AB; issue"
if issue_index == 0:
issue_nav.prev_issue_class = "unlinked-button"
prev_issue_link = ""
else:
prev_volume_number, prev_issue_number, discarded = issue_metadatas[issue_index-1]
prev_issue_link = "volume-%02d/issue-%02d/index.html" % (prev_volume_number, prev_issue_number)
issue_nav.prev_issue_html = "<a href='../../../%s'>%s</a>" % (prev_issue_link, default_prev_issue_html)
issue_nav.prev_issue_class = ""
default_next_issue_html = issue_nav.next_issue_html = "issue &#x00BB;"
if issue_index == last_issue_index:
issue_nav.next_issue_class = "unlinked-button"
next_issue_link = ""
else:
next_volume_number, next_issue_number, discarded = issue_metadatas[issue_index+1]
next_issue_link = "volume-%02d/issue-%02d/index.html" % (next_volume_number, next_issue_number)
issue_nav.next_issue_html = "<a href='../../../%s'>%s</a>" % (next_issue_link, default_next_issue_html)
issue_nav.next_issue_class = ""
last_page_link = "../index.html"
last_page_index = len(issue_pagedata)-1
for page_index, (page_type, page_dirname) in enumerate(issue_pagedata):
if issue_nav:
issue_nav.prev_article_class = "unlinked-button"
issue_nav.next_article_class = "unlinked-button"
issue_nav.prev_article_html = default_prev_article_html
issue_nav.next_article_html = default_next_article_html
set_prev = False
set_next = False
next_link = ""
# The article hotbar skips over the copyright page.
if page_dirname not in setting_website_hidden_issue_pages:
if page_index == last_page_index:
set_prev = True
else:
set_next = set_prev = True
if set_prev:
issue_nav.prev_article_html = "<a href='%s'>%s</a>" % (last_page_link, default_prev_article_html)
issue_nav.prev_article_class = ""
if set_next:
# The article hotbar skips over the copyright page.
j = page_index+1
while j < len(issue_pagedata) and issue_pagedata[j][1] in setting_website_hidden_issue_pages:
j += 1
if j < len(issue_pagedata):
next_link = "../"+ issue_pagedata[j][1] +"/index.html"
issue_nav.next_article_html = "<a href='%s'>%s</a>" % (next_link, default_next_article_html)
issue_nav.next_article_class = ""
generate_issue_page(issue_nav, volume_number, issue_number, year_number, month_number, page_type, page_dirname)
if issue_nav:
# The article hotbar skips over the copyright page.
if page_dirname not in setting_website_hidden_issue_pages:
last_page_link = "../"+ page_dirname +"/index.html"
if issue_nav:
if prev_issue_link:
issue_nav.prev_issue_html = "<a href='../../%s'>%s</a>" % (prev_issue_link, default_prev_issue_html)
issue_nav.prev_issue_class = ""
else:
issue_nav.prev_issue_html = default_prev_issue_html
issue_nav.prev_issue_class = "unlinked-button"
if next_issue_link:
issue_nav.next_issue_html = "<a href='../../%s'>%s</a>" % (next_issue_link, default_next_issue_html)
issue_nav.next_issue_class = ""
else:
issue_nav.next_issue_html = default_next_issue_html
issue_nav.next_issue_class = "unlinked-button"
issue_nav.prev_article_class = "unlinked-button"
issue_nav.next_article_class = ""
issue_nav.prev_article_html = default_prev_article_html
issue_nav.next_article_html = "<a href='%s'>%s</a>" % (issue_pagedata[0][1] +"/index.html", default_next_article_html)
generate_issue_toc(issue_nav, issue_metadata, issue_pagedata)
def generate_ebooks(issue_data):
"""
"" ebooks\volume-06\issue-01\index.html issue.pdf --verbose
"""
command_path = ""
command_path_guess = ""
if os.name == "nt":
command_path_guess = "c:\\Program Files (x86)\\Calibre2\\ebook-convert.exe"
if os.path.exists(command_path_guess):
command_path = command_path_guess
elif os.name == "posix":
command_path_guess = "/home1/disinter/opt/calibre/ebook-convert"
if os.path.exists(command_path_guess):
command_path = command_path_guess
if command_path == "":
print "Error: Unable to locate 'ebook-convert.exe', failed to generate ebooks."
print "... %s" % command_path_guess
return
standard_arguments = ""
standard_arguments += " --disable-font-rescaling"
standard_arguments += " --margin-bottom=72"
standard_arguments += " --margin-top=72"
standard_arguments += " --margin-left=72"
standard_arguments += " --margin-right=72"
standard_arguments += " --chapter=/"
standard_arguments += " --page-breaks-before=/"
standard_arguments += " --chapter-mark=rule"
standard_arguments += " --output-profile=default"
standard_arguments += " --input-profile=default"
standard_arguments += " --pretty-print"
standard_arguments += " --replace-scene-breaks=\"\""
standard_arguments += " --toc-filter=.*\[\d+\].*"
output_path = os.path.join("website", "files")
distutils.dir_util.mkpath(output_path)
issue_metadatas = issue_data.keys()
issue_metadatas.sort()
for issue_index, issue_metadata in enumerate(issue_metadatas):
issue_pagedata = issue_data[issue_metadata]
volume_number, issue_number, (year_number, month_number) = issue_metadata
print "Generating ebook volume %d, issue %d" % (volume_number, issue_number)
volume_path = os.path.join(setting_target_dirname, "volume-%02d" % volume_number)
issue_path = os.path.join(volume_path, "issue-%02d" % issue_number)
html_path = os.path.join(issue_path, "index.html")
output_basename = "imaginary-realities-v%02di%02d-%04d%02d" % (volume_number, issue_number, year_number, month_number)
for suffix in ("epub", "pdf"):
output_filename = output_basename +"."+ suffix
ret = subprocess.call([ command_path, html_path, os.path.join(output_path, output_filename) ])
print output_filename, ret
def get_article_block_content(volume_number, issue_number, page_dirname, block_name):
# Load the template.
jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader([
"templates", setting_base_template,
os.path.join("templates", "volume%02d_issue%02d" % (volume_number, issue_number), page_dirname)
]))
t = jinja2_env.get_template("index.html")
if block_name in t.blocks:
return next(t.blocks[block_name](None)).strip()
return ""
default_generation_targets = TARGET_WEBSITE, TARGET_EBOOK
def run(targets=None, disqus_data=None, reddit_data=None):
# TODO(rmtew): Make these non-global at some point. It's not really a problem, but it's messy.
global setting_target_dirname
global setting_use_minimised_files
global setting_website_hidden_issue_pages
global setting_generation_target
global setting_base_template
global jinja2_env
global data_disqus
global data_reddit
data_disqus = disqus_data
data_reddit = reddit_data
if targets is None:
targets = default_generation_targets
for setting_generation_target in targets:
if setting_generation_target not in templates_by_target:
print >> sys.stderr, "Unknown target:", setting_generation_target
sys.exit(1)
setting_base_template = templates_by_target[setting_generation_target]
setting_use_minimised_files = False
setting_target_dirname = None
setting_website_hidden_issue_pages = []
if setting_generation_target & TARGET_WEBSITE == TARGET_WEBSITE:
setting_target_dirname = "website"
setting_website_hidden_issue_pages.extend([ "copyright", "request-for-content" ])
if setting_generation_target & FLAG_ONLINE == FLAG_ONLINE:
setting_use_minimised_files = True
elif setting_generation_target & TARGET_EBOOK == TARGET_EBOOK:
setting_target_dirname = "ebooks"
jinja2_env = jinja2.Environment(loader=jinja2.FileSystemLoader([ 'templates', setting_base_template ]))
if os.path.exists(setting_target_dirname):
distutils.dir_util.remove_tree(setting_target_dirname)
if (setting_generation_target & TARGET_WEBSITE) == TARGET_WEBSITE:
generate_issues(issue_data)
generate_website()
elif (setting_generation_target & TARGET_EBOOK) == TARGET_EBOOK:
generate_issues(issue_data)
generate_ebooks(issue_data)
if __name__ == "__main__":
run()
# EOF