2015-05-25 07:04:55 +03:00
# CURRENT:
2015-05-17 08:38:09 +03:00
# TODO: Shared
2015-05-17 10:17:07 +03:00
# TODO: generate TARGET_EBOOK
2015-06-08 11:44:33 +03:00
# TODO: Send HTML & CSS to ebook format converter:
# TODO: pdf generation
2015-07-24 04:54:02 +03:00
# - 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.
2015-05-17 10:17:07 +03:00
# TODO: generate TARGET_WEBSITE
2015-07-24 04:54:02 +03:00
# 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.
2015-06-08 11:44:33 +03:00
# 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?
2015-07-24 04:54:02 +03:00
# TODO: RSS feed may need to include announcements.
# - add from text file.
# - edit in text file.
#
2015-05-16 06:48:25 +03:00
2015-05-17 07:22:56 +03:00
import calendar
2015-05-16 06:48:25 +03:00
import codecs
2015-06-08 11:44:33 +03:00
import distutils
2015-06-09 06:13:00 +03:00
import distutils . dir_util # Not needed on windows.
import distutils . file_util # Not needed on windows.
2015-06-04 05:25:32 +03:00
import email . utils
import json
import os
2015-05-16 06:48:25 +03:00
import shutil
2015-06-09 05:50:20 +03:00
import subprocess
2015-05-16 06:48:25 +03:00
import sys
import time
import jinja2
2015-06-04 05:25:32 +03:00
import feedformatter
2015-05-17 08:38:09 +03:00
2015-05-17 10:17:07 +03:00
FLAG_ONLINE = 1 << 31
2015-05-17 08:38:09 +03:00
TARGET_EBOOK = 1
2015-05-17 10:17:07 +03:00
TARGET_WEBSITE = 2
2015-05-17 08:38:09 +03:00
2015-05-17 09:19:19 +03:00
# This defines where to look for the base template for a given target.
2015-05-17 08:38:09 +03:00
templates_by_target = {
2015-06-08 11:44:33 +03:00
TARGET_EBOOK : os . path . join ( " templates " , " ebook " ) ,
TARGET_WEBSITE | FLAG_ONLINE : os . path . join ( " templates " , " website " ) ,
TARGET_WEBSITE : os . path . join ( " templates " , " website " ) ,
2015-05-17 08:38:09 +03:00
}
2015-06-04 12:14:46 +03:00
""" Variable to configure for generation of final result with side-effects. """
2015-06-09 05:59:51 +03:00
setting_finalise = True
2015-06-09 06:05:09 +03:00
2015-06-08 11:44:33 +03:00
setting_domain_name = " journal.imaginary-realities.com "
2015-05-16 06:48:25 +03:00
PAGE_OTHER = 1
PAGE_ARTICLE = 2
issue_data = {
2015-06-08 11:44:33 +03:00
# (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 " ) ,
2015-06-08 11:49:25 +03:00
( PAGE_OTHER , " request-for-content " ) ,
2015-06-08 11:44:33 +03:00
( 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 " ) ,
] ,
2015-07-24 04:54:02 +03:00
( 7 , 3 , ( 2015 , 7 ) ) : [
( PAGE_OTHER , " introduction " ) ,
( PAGE_OTHER , " copyright " ) ,
2015-07-27 11:20:00 +03:00
( PAGE_ARTICLE , " a-text-mud-with-a-working-ecology-system " ) ,
2015-07-24 04:54:02 +03:00
( PAGE_ARTICLE , " dispelling-the-gloom " ) ,
( PAGE_ARTICLE , " how-integral-are-letters-and-text-to-ascii-gaming " ) ,
( PAGE_ARTICLE , " legend-and-the-lore " ) ,
2015-07-27 11:20:00 +03:00
( PAGE_ARTICLE , " the-bonds-of-mudding " ) ,
2015-07-24 04:54:02 +03:00
( PAGE_ARTICLE , " the-mercurial-temperament-at-the-end-of-the-world " ) ,
2015-07-27 11:20:00 +03:00
( PAGE_ARTICLE , " where-do-i-begin " ) ,
2015-07-24 04:54:02 +03:00
( PAGE_OTHER , " request-for-content " ) ,
( PAGE_OTHER , " staff " ) ,
]
2015-05-16 06:48:25 +03:00
}
class TemplateParameters ( object ) :
2015-06-08 11:44:33 +03:00
pass
2015-05-16 06:48:25 +03:00
def init_template_data ( tp ) :
2015-06-08 11:44:33 +03:00
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
2015-06-09 02:29:37 +03:00
tp . target_is_website = ( setting_generation_target & TARGET_WEBSITE ) == TARGET_WEBSITE
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
def get_latest_issue_data ( tp ) :
2015-06-08 11:44:33 +03:00
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 "
2015-05-16 06:48:25 +03:00
def get_back_issues_data ( tp ) :
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
def generate_website_index_page ( ) :
2015-07-29 12:22:06 +03:00
global data_disqus
2015-06-08 11:44:33 +03:00
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 "
2015-07-29 12:22:06 +03:00
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 )
2015-06-08 11:44:33 +03:00
html = t . render ( tp = tp )
with codecs . open ( output_path , " wb " , " utf-8 " ) as f :
f . write ( html )
2015-05-16 06:48:25 +03:00
def generate_website_contact_page ( ) :
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
2015-05-25 07:04:55 +03:00
def generate_website_links_page ( ) :
2015-06-08 11:44:33 +03:00
t = jinja2_env . get_template ( " links.html " )
output_path = os . path . join ( setting_target_dirname , " links.html " )
2015-05-25 07:04:55 +03:00
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
def generate_website_copyright_page ( ) :
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
def generate_website_contribute_page ( ) :
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
2015-06-04 05:25:32 +03:00
def generate_website_rss ( ) :
2015-06-08 11:44:33 +03:00
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 " ) )
2015-06-09 05:59:51 +03:00
changes_made = False
2015-06-08 11:44:33 +03:00
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.
2015-06-09 05:59:51 +03:00
changes_made = True
2015-06-08 11:44:33 +03:00
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 )
2015-06-09 05:59:51 +03:00
download_link = feed . feed [ " link " ] + " files/ "
2015-06-08 11:44:33 +03:00
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 )
2015-06-09 05:59:51 +03:00
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 )
2015-06-08 11:44:33 +03:00
item [ " link " ] = missing_link
item [ " pubDate " ] = time . time ( )
item [ " guid " ] = " %d " % ( time . time ( ) * 100 )
feed_items . append ( item )
feed . items . append ( item )
2015-06-09 05:59:51 +03:00
changes_made = True
2015-06-08 11:44:33 +03:00
if setting_finalise :
2015-06-09 05:59:51 +03:00
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. "
2015-06-08 11:44:33 +03:00
# Generate the RSS2 feed.
feed . format_rss2_file ( os . path . join ( setting_target_dirname , " feed_rss2.xml " ) )
2015-06-04 05:25:32 +03:00
2015-05-16 06:48:25 +03:00
### ISSUE GENERATION
def generate_website ( ) :
2015-06-08 11:44:33 +03:00
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 " ) :
2015-06-08 11:49:25 +03:00
distutils . dir_util . copy_tree ( os . path . join ( " templates " , " website " , dirname ) , os . path . join ( setting_target_dirname , dirname ) )
2015-05-17 10:17:07 +03:00
2015-06-03 09:31:40 +03:00
def generate_issue_page ( issue_nav , volume_number , issue_number , year_number , month_number , page_type , page_dirname ) :
2015-06-08 11:44:33 +03:00
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 )
2015-05-16 06:48:25 +03:00
2015-06-03 09:31:40 +03:00
def generate_issue_toc ( issue_nav , issue_metadata , issue_pagedata ) :
2015-06-08 11:44:33 +03:00
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 )
2015-05-18 10:39:39 +03:00
2015-05-16 06:48:25 +03:00
def generate_issues ( issue_data ) :
2015-06-08 11:44:33 +03:00
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
2015-06-09 05:50:20 +03:00
print " Generating issue volume %d , issue %d " % ( volume_number , issue_number )
2015-06-08 11:44:33 +03:00
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 " )
2015-06-08 11:49:25 +03:00
distutils . dir_util . copy_tree ( images_input_path , images_output_path )
2015-06-08 11:44:33 +03:00
# 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 ) :
2015-06-08 11:49:25 +03:00
if parent_template_name == " website " and entry_name == " images " :
# There are a lot of images we do not need.
2015-06-08 11:44:33 +03:00
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 = " « article "
issue_nav . prev_article_class = " "
default_next_article_html = issue_nav . next_article_html = " article » "
issue_nav . next_article_class = " "
# Inter-issue navigation button setup.
default_prev_issue_html = issue_nav . prev_issue_html = " « 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 » "
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 )
2015-05-16 06:48:25 +03:00
2015-06-09 05:50:20 +03:00
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 %02d i %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
2015-05-16 06:48:25 +03:00
def get_article_block_content ( volume_number , issue_number , page_dirname , block_name ) :
2015-06-08 11:44:33 +03:00
# 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 " "
2015-05-16 06:48:25 +03:00
2015-07-29 12:22:06 +03:00
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
2015-06-09 06:05:09 +03:00
2015-07-29 12:22:06 +03:00
for setting_generation_target in targets :
2015-06-09 06:05:09 +03:00
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 )
2015-06-08 11:44:33 +03:00
2015-06-09 06:05:09 +03:00
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 )
2015-06-08 11:44:33 +03:00
2015-07-29 12:22:06 +03:00
if __name__ == " __main__ " :
run ( )
2015-06-04 08:29:02 +03:00
# EOF