Separation of site from code

Working on separating the Lunatics site data from the
LunaGen source code, and replacing it with test code only.
This commit is contained in:
Terry Hancock 2022-06-28 01:27:13 -05:00
parent b836bef771
commit 158718a650
92 changed files with 628 additions and 1377 deletions

BIN
LunaGen/lunagen_profile.txt Normal file

Binary file not shown.

View File

479
LunaGen/src/lunagen_backup.py Executable file
View File

@ -0,0 +1,479 @@
#!/usr/bin/python3
# encoding: utf-8
'''
lunagen -- "Lunatics!" Project Release Site Generator
LunaGen generates a small static HTML website based on YAML
data documents containing the key release information. This
generates an index.html file containing the episode lists
for all series, individual release pages for each episode,
and additional pages for character list and story background.
This is meant to be a fan-focused site.
It also contains affiliate link, sponsor, advertising, and
other fundraising elements.
@author: Terry Hancock
@copyright: 2019 Anansi Spaceworks.
@license: GNU General Public License, version 2.0 or later. (Python code)
Creative Commons Attribution-ShareAlike, version 3.0 or later. (Website Templates).
@contact: digitante@gmail.com
'''
import sys
import os
#from shutil import copytree, rmtree
from distutils.dir_util import remove_tree, copy_tree
from optparse import OptionParser
import random
from collections import OrderedDict
import yaml
import jinja2
import lunagen
lunagen.demo()
class Config(object):
"""
Installation configuration variables.
TODO: Probably change this to load from a YAML file in the future.
"""
__all__ = []
__version__ = 0.1
__date__ = '2019-09-19'
__updated__ = '2019-09-19'
DEBUG = True
TESTRUN = False
PROFILE = False
THEMES = '../themes'
class LunaGen(jinja2.Environment):
"""
Generator for a LunaGen site, based on contents of srcdir:
<srcdir>/data - YAML files (handwritten content)
<srcdir>/templates - Jinja2 site templates
<srcdir>/skeleton - unchanging parts of the site (copied)
The new site is created in <tgtdir>.
"""
def __init__(self, srcdir, tgtdir=None, verbosity=0):
self.srcdir = os.path.abspath(srcdir)
if not tgtdir:
self.tgtdir = os.path.join(self.srcdir, 'site')
else:
self.tgtdir = os.path.abspath(tgtdir)
self.datadir = os.path.join(self.srcdir, 'data')
self.templates = os.path.join(self.srcdir, 'templates')
self.skeleton = os.path.join(self.srcdir, 'skeleton')
self.verbose = verbosity
if self.verbose:
print("Source directory: %s" % self.srcdir)
print("Target directory: %s" % self.tgtdir)
print("YAML content should be in: %s" % self.datadir)
print("Jinja2 templates should be in: %s" % self.templates)
print("Skeleton website should be in: %s" % self.skeleton)
#TODO: Could make sure these directories exist
# Load up the data from YAML files:
self._load_sitedata()
self._load_theme()
self._load_affiliates()
self._load_softwarelist()
self._load_products()
self._load_serieslist()
super().__init__(
loader=jinja2.ChoiceLoader([
jinja2.FileSystemLoader(os.path.join(self.datadir, 'templates')),
jinja2.FileSystemLoader(self.theme['path']),
jinja2.FileSystemLoader(self.templates)]),
autoescape=jinja2.select_autoescape(['html','xml']))
@staticmethod
def _paginate(seq, pagesize):
"""
Given a sequence of objects, break it into a book of
pages, each containing no more than pagesize objects:
>>> test = [1,'2','three', 4, 5, 'six', 'seven', 8, 9, True, False, None, 0]
>>> LunaGen._paginate(test, 4)
[[1, '2', 'three', 4], [5, 'six', 'seven', 8], [9, True, False, None], [0]]
>>>
"""
book = []
page = []
for i,ob in enumerate(seq):
if i%pagesize==0:
if i>0: book.append(page)
page = []
page.append(ob)
if len(page)>0:
book.append(page)
return book
@staticmethod
def _paginate_sponsors(series, episode):
"""
Regroup sponsors into pages which:
- Contain only one kind of sponsor
- Contain no more than the 'page' limit number of sponsors per page
- Are tagged with the sponsortype so we can find the right tempate for them:
>>> series = {'sponsortypes':
... {'A':{'page':1,'limit':1},
... 'B':{'page':3, 'limit':10},
... 'C':{'page':4, 'limit':20}}}
...
>>> episode = {'sponsors':
... {'A':list(range(2)),
... 'B':list(range(7)),
... 'C':list(range(22))}}
...
>>> LunaGen._paginate_sponsors(series, episode)
[('A', [0]), ('B', [0, 1, 2]), ('B', [3, 4, 5]), ('B', [6]), ('C', [0, 1, 2, 3]), ('C', [4, 5, 6, 7]), ('C', [8, 9, 10, 11]), ('C', [12, 13, 14, 15]), ('C', [16, 17, 18, 19])]
>>>
"""
paged_sponsors = []
for spkey, sponsortype in series['sponsortypes'].items():
if spkey not in episode['sponsors']:
episode['sponsors'][spkey] = []
#if 'excludes' in sponsortype:
# for excluded in sponsortype['excludes']:
# if excluded in episode['sponsors'] and episode['sponsors'][excluded]:
# print("WARNING: excluded sponsortype %s will be ignored, because of existing %s." %
# (excluded, spkey))
if 'page'in sponsortype:
paged = LunaGen._paginate(
episode['sponsors'][spkey][:sponsortype['limit']],
sponsortype['page'])
tags = [spkey] * len(paged)
paged_sponsors.extend(zip(tags, paged))
return paged_sponsors
@staticmethod
def _fix_series(series):
"""
Modify series data to correct certain datatypes that are not
natively supported by YAML (like OrderedDict):
>>> series = {'credits':{
... 'a':{'labels':'ordered'},
... 'b':{'labels':[['A','-A-'],['B','-B-']]}}}
...
>>> LunaGen._fix_series(series)
>>> series['credits']['b']['labels']
OrderedDict([('A', '-A-'), ('B', '-B-')])
>>>
"""
for key, credit in series['credits'].items():
if type(credit['labels']) != type(''):
credit['labels']=OrderedDict(credit['labels'])
def _collect_stylesheets(self, *extras):
"""
Collect a list of unique stylesheets from various stylesheet
requirements from theme, site, and data from extra pages.
"""
stylesheets = []
stylesheets.extend(self.theme['stylesheets'])
stylesheets.extend(self.sitedata['stylesheets'])
for extra in extras:
if 'stylesheets' in extra:
stylesheets.extend(extra['stylesheets'])
stylesheets = [s for i,s in enumerate(stylesheets) if s not in stylesheets[:i]]
return stylesheets
def _load_sitedata(self):
if self.verbose: print("Loading global site data.")
with open(os.path.join(self.datadir, 'site.yaml'), 'rt') as sitedatafile:
self.sitedata = yaml.load(sitedatafile)
def _load_theme(self):
if self.verbose: print("Loading theme data.")
self.theme = { 'stylesheets':[] } # Default values
themedir = os.path.join(Config.THEMES, self.sitedata['theme'])
if not os.path.exists(themedir):
raise FileNotFoundError("Theme directory %s not found!" % themedir)
with open(os.path.join(themedir, 'theme.yaml'), 'rt') as themedatafile:
self.theme.update(yaml.load(themedatafile))
self.theme['path'] = themedir
def _load_affiliates(self):
if self.verbose: print("Loading affiliates data.")
try:
with open(os.path.join(self.datadir, 'affiliates.yaml')) as aff_file:
affiliates = yaml.load(aff_file)
stylesheets = self.sitedata['stylesheets']
self.sitedata.update(affiliates)
self.sitedata['stylesheets'] = self._collect_stylesheets(affiliates)
self.sitedata['affiliates'] = random.sample(
affiliates['affiliates'], min( int(affiliates['affiliates_at_once']),
len(affiliates['affiliates'])))
except FileNotFoundError:
print("No affiliates.yaml file, so affiliates list is empty.")
self.sitedata['affiliates'] = []
def _load_softwarelist(self):
if self.verbose: print("Loading software data.")
try:
with open(os.path.join(self.datadir, 'software.yaml')) as sw_file:
softwarelist = yaml.load(sw_file)
stylesheets = self.sitedata['stylesheets']
self.sitedata.update(softwarelist)
self.sitedata['stylesheets'] = self._collect_stylesheets(softwarelist)
except FileNotFoundError:
print("No software.yaml file, so software list is empty.")
self.sitedata['softwarelist'] = []
def _load_products(self):
if self.verbose: print("Loading store products data.")
try:
with open(os.path.join(self.datadir, 'products.yaml')) as prod_file:
products = yaml.load(prod_file)
stylesheets = self.sitedata['stylesheets']
self.sitedata.update(products)
self.sitedata['stylesheets'] = self._collect_stylesheets(products)
except FileNotFoundError:
print("No products.yaml file, so software list is empty.")
self.sitedata['products'] = []
def _load_serieslist(self):
if self.verbose: print("Loading series data")
try:
with open(os.path.join(self.datadir, 'episodes', 'series.yaml'),'rt') as seriesfile:
self.serieslist = yaml.load(seriesfile)['serieslist']
for series in self.serieslist:
self._fix_series(series)
episodes = []
seriesdir = os.path.join(self.datadir, 'episodes', series['directory'])
episode_filenames = [f for f in os.listdir(seriesdir) if f.endswith('.yaml')]
for episode_filename in episode_filenames:
if self.verbose: print("Loading episode from %s" % episode_filename)
with open(os.path.join(seriesdir, episode_filename), 'rt') as episode_file:
episodes.append(yaml.load(episode_file))
# Sort by episode number specified in the files:
try:
episodes.sort(key=lambda a: int(a['episode']))
except KeyError:
print("Some episode YAML files may not have an 'episode' number entry?")
series['episodes'] = episodes
except FileNotFoundError:
print("No series.yaml file, so no series loaded.")
self.sitedata['serieslist'] = []
def _copy_skeleton(self):
if os.path.exists(self.tgtdir):
remove_tree(self.tgtdir, verbose=self.verbose)
if self.verbose: print("Copying the theme base.")
copy_tree(os.path.join(self.theme['path'], 'base'), self.tgtdir, verbose=self.verbose)
if self.verbose: print("Copying the skeleton site.")
copy_tree(self.skeleton, self.tgtdir, verbose=self.verbose)
def _gen_simple_page(self, pagename, stylesheets=()):
"""
Generates a simple page with 1:1:1 Jinja2+YAML+CSS.
The YAML and CSS pages are optional. If no file exists
for them, they will be ignored and the page generated
with only the template and global data and/or style.
"""
if self.verbose: print("Creating '%s' page" % pagename)
jinja2_name = pagename + '.j2'
yaml_path = os.path.join(self.datadir, pagename+'.yaml')
css_path = os.path.join(self.tgtdir, pagename+'.css')
# Assumes skeleton already copied
data = {} # Defaults can be set here
data.update(self.sitedata) # Global data
if os.path.exists(yaml_path):
with open(yaml_path, 'rt') as yaml_file:
data.update(yaml.load(yaml_file)) # Page data
data['stylesheets'] = self._collect_stylesheets(data)
# Add CSS if not already present:
if os.path.exists(css_path) and pagename not in data['stylesheets']:
data['stylesheets'].append(pagename)
if self.verbose: print("Generating '%s.html' from template." % pagename)
html = self.get_template(jinja2_name).render(data)
with open(os.path.join(self.tgtdir, pagename+'.html'), 'wt') as page:
page.write(html)
def _gen_index(self):
"""
Generate an index page, if the skeleton doesn't already have one.
"""
if not os.path.exists(os.path.join(self.tgtdir, 'index.html')):
if self.verbose: print("Generating the Index page.")
data = {}
data.update(self.sitedata)
data['next'] = next # Adds iterator capability
data['stylesheets'] = self._collect_stylesheets(self.sitedata['stylesheets'])
if 'episode_as_index' in self.sitedata and self.sitedata['episode_as_index']:
data['serieslist'] = self.serieslist
data['banners'] = iter(['affiliates_banner.j2',
'store_banner.j2',
'sponsoropps_banner.j2'])
data['stylesheets'].extend(self._collect_stylesheets(
self.sitedata['episode_list_page']))
html = self.get_template('index.j2').render(data)
with open(os.path.join(self.tgtdir, 'index.html'), 'wt') as page:
page.write(html)
else:
if self.verbose: print("Found 'index.html', so not generated.")
def _gen_episode_list_page(self):
"""
Generate a page linking to all of the individual episodes,
grouped into "series" (or "seasons").
#Currently hard-coded to be saved as 'index.html' for the site.
"""
if self.verbose: print("Generating the Index (Episode List) page.")
if 'render_as' in self.sitedata['episode_list_page']:
render_as = self.sitedata['episode_list_page']['render_as']
else:
render_as = 'index.html'
data = {}
data.update(self.sitedata)
data['serieslist'] = self.serieslist
data['banners'] = iter(['affiliates_banner.j2', 'store_banner.j2', 'sponsoropps_banner.j2'])
data['stylesheets'] = self._collect_stylesheets(self.sitedata['episode_list_page'])
data['next'] = next # Adds iterator capability
html = self.get_template('episode_list.j2').render(data)
with open(os.path.join(self.tgtdir, render_as), 'wt') as page:
page.write(html)
def _gen_episode_pages(self):
"""
Generate a page for each episode in each series.
"""
if self.verbose: print("Generating episode pages...")
if 'stylesheets' in self.sitedata['episode_pages']:
stylesheets = self.sitedata['episode_pages']['stylesheets']
else:
stylesheets = []
for series in self.serieslist:
for episode in series['episodes']:
paged_sponsors = self._paginate_sponsors(series, episode)
episode['paged_sponsors'] = iter(paged_sponsors)
data = {}
data.update(self.sitedata)
data['series'] = series
data['episode'] = episode
data['stylesheets'] = self._collect_stylesheets(self.sitedata['episode_pages'],episode)
data['next'] = next
data['banners'] = ['affiliates_banner.j2']
html = self.get_template('episode_page.j2').render(data)
filename = episode['series'] +'E' + ('%2.2d' % int(episode['episode'])) + '.html'
os.makedirs(os.path.join(self.tgtdir, series['directory']), exist_ok=True)
with open(os.path.join(self.tgtdir, series['directory'], filename), 'wt') as page:
page.write(html)
def gensite(self):
"""
Generate the site, using the data we've accumulated.
"""
self._copy_skeleton()
for page in self.sitedata['simple_pages']:
self._gen_simple_page(page)
if self.sitedata['serieslist']:
self._gen_episode_list_page()
self._gen_episode_pages()
else:
print("Not generating series & episode pages: serieslist empty.")
self._gen_index()
def main(argv=None):
'''Command line options.'''
program_name = os.path.basename(sys.argv[0])
program_version = "v0.1"
program_build_date = "%s" % Config.__updated__
program_version_string = '%%prog %s (%s)' % (program_version, program_build_date)
program_longdesc = '''\
LunaGen is a static HTML website generator designed for releasing
a series of episodes (technically: a series of series of episodes).
Data is authored using the YAML structured data language, which allows
for episode metadata and descriptions to be written in a human-friendly
format, which is then formatted into HTML using Jinja2 templates.
Once generated, the site is static and can simply be uploaded to a
standard web server with minimal or no configuration (like a static web host).
It was originally created to generate the release pages for
Anansi Spaceworks' "Lunatics!" series.
For details, please see the 'examples' and 'doc' directories.
'''
program_license = "Copyright 2019 Terry Hancock (Anansi Spaceworks) \
Licensed under the GNU General Public License, version 2.0\n"
if argv is None:
argv = sys.argv[1:]
#try:
# setup option parser
parser = OptionParser(version=program_version_string, epilog=program_longdesc, description=program_license)
parser.add_option("-i", "--in", dest="src", help="set input path [default: %default]", metavar="FILE")
parser.add_option("-o", "--out", dest="tgt", help="set output path [default: %default]", metavar="FILE")
parser.add_option("-v", "--verbose", dest="verbose", action="count", help="set verbosity level [default: %default]")
# set defaults
parser.set_defaults(tgt="./site", src=".")
# process options
(opts, args) = parser.parse_args(argv)
if opts.verbose > 0:
print("verbosity level = %d" % opts.verbose)
if opts.src:
print("src = %s" % opts.src)
if opts.tgt:
print("tgt = %s" % opts.tgt)
lunagen = LunaGen(opts.src, opts.tgt, opts.verbose)
lunagen.gensite()
# except Exception as e:
# indent = len(program_name) * " "
# sys.stderr.write(program_name + ": " + repr(e) + "\n")
# sys.stderr.write(indent + " for help use --help")
# return 2
if __name__ == "__main__":
if Config.DEBUG:
#sys.argv.append("-h")
sys.argv.append("-v")
if Config.TESTRUN:
import doctest
doctest.testmod()
if Config.PROFILE:
import cProfile
import pstats
profile_filename = 'lunagen_profile.txt'
cProfile.run('main()', profile_filename)
statsfile = open("profile_stats.txt", "wb")
p = pstats.Stats(profile_filename, stream=statsfile)
stats = p.strip_dirs().sort_stats('cumulative')
stats.print_stats()
statsfile.close()
sys.exit(0)
sys.exit(main())

View File

@ -1,55 +0,0 @@
# Affiliates Ad data
# This is a MOCK-UP, not real affiliates.
# (Because I don't have any yet)
---
stylesheets:
- affiliates
# It's awkward to have too many affiliate links at one time, so
# the script will choose a number of them at random on each refresh
# we need to tell it how many we want:
affiliates_at_once: 7
affiliates:
- name: 123posters
url: http://www.123posters.com/
img: 123posters.png
- name: Amazon
url: http://amazon.com
img: amazon.png
- name: Barnes & Noble
url: https://www.barnesandnoble.com/
img: barnes_noble.png
- name: Better World Books
url: https://www.betterworldbooks.com/
img: betterworldbooks.png
- name: Crayola
url: https://www.crayola.com/
img: crayola.png
- name: Humble Bundle
url: https://www.humblebundle.com/
img: humble.png
- name: Kiwi Crate
url: https://www.kiwico.com/
img: kiwicrate.png
- name: Linux Foundation Training Programs
url: https://www.linuxfoundation.org/
img: linux_foundation.png
- name: Lonely Planet
url: https://www.lonelyplanet.com/
img: lonelyplanet.png
- name: Red Hat
url: https://www.redhat.com/en
img: redhat.png
- name: Lenovo
url: https://www.lenovo.com/us/en/pc
img: lenovo.png

View File

@ -1,147 +0,0 @@
# Affiliates Ad data
# This is a MOCK-UP, using popular Free Culture / Open Source projects
# We do not have any actual affiliation with these sites
#
---
stylesheets:
- affiliates
# It's awkward to have too many affiliate links at one time, so
# the script will choose a number of them at random on each refresh
# we need to tell it how many we want:
affiliates_at_once: 7
affiliates_message: >
We benefit when you support these projects and services!
affiliates:
- name: Ardour
url: https://ardour.org
img: ardour.png
type: Software We Use
- name: Audacity
url: https://audacityteam.org
img: audacity.png
type: Software We Use
- name: Blender
url: https://blender.org
img: blender.png
type: Software We Use
- name: Blender Cloud
url: https://cloud.blender.org
img: blender_cloud.png
type: Open Movie Platform
- name: BlendSwap
url: https://blendswap.com
img: blendswap.png
type: Shared Asset Archive
- name: Creative Commons
url: https://www.creativecommons.org
img: creativecommons.png
type: Free Culture Advocacy Group
- name: Debian
url: https://debian.org
img: debian.png
type: Software We Use
- name: Ethic Cinema
url: http://ethiccinema.org
img: ethiccinema.png
type: Free Culture Advocacy Group
- name: Free Software Foundation
url: https://www.fsf.org
img: freesoftwarefoundation.png
type: Free Software Advocacy Group
- name: Free Sound
url: https://freesound.org
img: freesound.png
type: Shared Asset Archive
- name: GIMP
url: https://gimp.org
img: gimp.png
type: Software We Use
- name: Inkscape
url: https://inkscape.org
img: inkscape.png
type: Software We Use
- name: Internet Archive
url: https://archive.org
img: internet_archive.png
type: Shared Asset Archive
- name: Jamendo
url: https://jamendo.com
img: jamendo.png
type: Shared Asset Archive
- name: Kdenlive
url: https://kdenlive.org
img: kdenlive.png
type: Software We Use
- name: Krita
url: https://krita.org
img: krita.png
type: Software We Use
- name: Mastodon
url: http://mastodon.social
img: mastodon.png
type: Social Media Platform We Use
- name: Morevna Project
url: https://morevnaproject.org
img: morevnaproject.png
type: Free Culture Project
- name: MusOpen
url: https://musopen.org
img: musopen.png
type: Shared Asset Archive
- name: Olive Video Editor
url: https://olivevideoeditor.org
img: olivevideoeditor.png
type: Software We Use
- name: Public Domain Files
url: http://www.publicdomainfiles.com
img: publicdomainfiles.png
type: Shared Asset Archive
- name: Public Knowledge
url: https://publicknowledge.org
img: publicknowledge.png
type: Free Culture Advocacy Group
- name: Question Copyright
url: https://questioncopyright.org
img: questioncopyright.png
type: Free Culture Advocacy Group
- name: Software Freedom Conservancy
url: https://sfconservancy.org
img: sfconservancy.png
type: Free Software Advocacy Group
- name: Ubuntu Studio
url: https://ubuntustudio.org
img: ubuntu_studio.png
type: Software We Use
- name: Urchn
url: https://urchn.org
img: urchn.png
type: Free Culture Studio

View File

@ -1,227 +0,0 @@
# Data for the character list page
---
stylesheets:
- bkg_moon_iridium
characters:
- name: Hiromi
fullname: Hiromi Aoki Lerner
img: hiromi_render_portrait.png
born: 2001
first_episode: 1
desc: >
Hiromi Lerner was a medical student and a concert
pianist when she first learned about the International
Space Foundation's project to put a colony on the Moon.
She's had a life-long interest in space (stemming partly
from her father, who owns a small aerospace business in
Torrance, California), but her main motivation is to
humanize the project and establish a comfortable home
on the Moon. She idolizes her husband Rob Lerner, but
also recognizes that he often has his head in the clouds,
and is not always the most stable man. She does a lot to
keep him grounded.
She's a traditionalist when it comes to home, decor,
and fashion, and has an active artistic interest in
integrating Japanese traditionalist aesthetics with
her technological lifestyle. She also sometimes sees
herself in terms of American western pioneers, who she
feels a lot of connection with as a pioneer on a new
frontier.
relations:
husband: Rob Lerner
daughter: Georgiana Lerner
father: David Aoki
mother: Ryoko Takamura
- name: Rob
fullname: John Robert Lerner
img: rob_render_portrait.png
born: 1993
first_episode: 2
desc: >
Rob Lerner is a dreamer who has always been fascinated
with the idea of living on another world. He grew up
reading (and watching) science fiction, and chose
mechanical engineering as a major in college. He's originally
from Texas, although he's lived in many parts of the US
Southwest during his life.
He tends to be focused on big picture ideas, although he
can also become bogged down in technical details and tends
to see problems through his engineering lens, which sometimes
leads him to struggle with more organic problems. His personality
is somewhat mercurial, prone to manic obsessions and depression
when things don't work out as he hopes.
He has a great enthusiasm for humanity in the abstract, but
often finds real individual humans hard to get along with. He
doesn't quite understand what he did to deserve the loyalty
and affection of Hiromi, but he's determined to keep doing it.
He founded the International Space Foundation which sponsors
the colony, and his place there is largely connected to that
status. He's seen as a kind of spiritual leader to the rest,
but isn't necessarily formally in charge.
relations:
wife: Hiromi Lerner
daughter: Georgiana Lerner
- name: Anya
fullname: Anna Anatolyeva Titova / Anna Titova-Farmer (US)
img: anya_render_portrait.png
born: 2005
first_episode: 3
desc: >
Anya Titova (also known as Anya Farmer or Anya Titova-Farmer,
but she uses her well-known maiden name professionally) is
the youngest child and only daughter of the billionaire co-owner of
a major space company (RK Cosmos), Anatoly Titov (his brother
Konstantin is also a major shareholder, as well being largely
in charge of research and development), and granddaughter of
Igor Titov who founded the company.
Unlike her older brothers, Sergei and Gregor, she was not
pressured to work as a cosmonaut, although she has had
extensive pilot training as a kind of family expectation.
She's lived a very privileged life, and was very much a rich
party girl in her youth. She liked fast cars and flashy
technology, but has increasingly wanted to make an identity
for herself. In her early twenties, she established her own
satellite company, and has used the profits to press her
new interest in space development.
She met Josh Farmer at a conference on space agriculture
sponsored by Rob Lerner's ISF, and there was immediate
chemistry her and Josh, which led to them getting married
and having a child not long after. But Anya never really
slowed down in her career, simply turning her efforts
more and more directly towards the ISF project.
Her family regards her interest in this project amusingly
"domestic", and tease her about it, but this will not stop
her. The more menial aspects of frontier life are a hard
challenge for her to adapt to, but she's managing.
She and Rob became co-conspirators on founding the project,
and she largely brought in the money and the corporate
connections to make it happen -- partly on the condition that
she and her family are in on this first colony.
relations:
husband: Josh Farmer
son: Tim Farmer
father: Anatoly Titov
brothers:
- Sergei Titov
- Gregor Titov
grandfather: Igor Titov
- name: Josh
fullname: Joshua Randall Farmer
img: josh_render_portrait.png
born: 2004
first_episode: 2
desc: >
Josh Farmer is amused at his appropriate name, as he
is indeed from a family of Farmers in the US Midwest. He
has a lot of Middle-American attitudes and values, but
he is the one who went to college. In fact, he has a
doctorate in agricultural science, though he doesn't
really like to be called "Doctor Farmer".
His specialty is space agriculture, and he knows just
about everything that anyone knows about how to grow
crops in space, and he's got a pretty fair knowledge of
animal husbandry as well, largely from his youth, growing
up on a farm.
He and his wife Anya seem like complete opposites, but
in fact, they share a lot of basic values, and so their
relationship is more complementary than oppositional. But
it's no question that Josh's quiet stoic outlook on life
makes an intense contrast with Anya's firebrand personality
and outspokenness.
Rob Lerner recruited Josh early on in the Lunar Independent
Biospherics Research Experiment (LIBRE) -- the Earthly
prototype the ISF colony is based on, early on, and he
has been instrumental to the planning and operation of the
project.
relations:
wife: Anya Titova
son: Tim Farmer
- name: Tim
fullname: Igor Timothy Farmer
img: tim_render_portrait.png
born: 2026
first_episode: 2
desc: >
Tim does not like his first name, Igor, which Anya gave
him in honor of his great-grandfather, and prefers to
stick with Tim. His mother still calls him "Igor", though.
He did not exactly choose to be a Lunar colonist, though
his chosen form of rebellion (promoting Mars colonization)
betrays a bit of his pride in his family and situation. It's
also true that he was old enough to have stayed with one
of his uncles' families had he really not wanted to go.
He is very much aware of the social deprivation of being
"literally the only teenager on the entire planet", and
he spends a lot of his time online, interacting with his
friends in VR communities on the "Great Global Grid" which
he jokes is now th "Great Galactic Grid". He has a large
following online, including a lot of teenage girls, who
he has a not-entirely-ethical attitude towards, much to
his mother's frustration, and a somewhat unhealthy connection
to a piece of anime-inspired "virtual girlfriend" software,
known as "Momo Aiai".
He spends a lot of time hanging out with Georgiana, who is
a little like a sister, given how close their living
arrangements are, but they're too far apart in age to have
really common interests.
relations:
father: Josh Farmer
mother: Anya Titova
- name: Georgiana
fullname: Georgiana Lerner
img: georgiana_render_portrait.png
born: 2033
first_episode: 1
desc:
Georgiana is a very quiet, introspective girl, who likes to
play with her bunny doll and secretly misses Earth, though
she's also excited about the prospect of living on the Moon,
and doesn't want to disappoint her parents.
She's still at a young enough age for magical thinking, and
sometimes invents her own "mythology" to explain how her
world works, ranging from insightful to woefully incorrect,
as with most children her age.
She's eager to learn new skills and adapts pretty quickly to
life in the colony.
relations:
mother: Hiromi Lerner
father: Rob Lerner

View File

@ -1,35 +0,0 @@
# Gumroad Store product links
---
stylesheets:
- products
products:
- name: Books
desc: Artbooks, writers guide, and more.
url: http://gumroad.com/anansispace
img: store_books.png
- name: Hard Media
desc: Video on DVD or flash media. Soundtrack on CD or vinyl.
url: http://gumroad.com/anansispace
img: store_hardmedia.png
- name: Posters
desc: Decorate your wall with posters and banners.
url: http://gumroad.com/anansispace
img: store_posters.png
- name: Subscriptions
desc: Subscribe to keep up to date, or become a patron for one episode.
url: http://gumroad.com/anansispace
img: store_subscriptions.png
- name: Novelties
desc: Collectible novelties and toys.
url: http://gumroad.com/anansispace
img: store_novelties.png
- name: Digital Perks
desc: Wallpapers, digital design, 3D printing, custom products.
url: http://gumroad.com/anansispace
img: store_digitalperks.png

View File

@ -1,36 +1,22 @@
# Global data for the site # Global data for the site
# ALL templates will have access to these # ALL templates will have access to these
--- ---
sitename: lunatics sitename: series_test
sitetitle: Lunatics! sitetitle: Series Test
imgdir: images imgdir: images
theme: lunatics theme: default
stylesheets:
- products
- affiliates
episode_list_page: episode_list_page:
render_as: index.html render_as: index.html
stylesheets: stylesheets:
- main - main
- credits - credits
- affiliates
- series - series
- products
- bkg_moon_iridium
episode_pages: episode_pages:
stylesheets: stylesheets:
- main - main
- credits - credits
- affiliates
- products
- episode - episode
- sponsors
simple_pages:
- characters
- universe
- sponsorship

View File

@ -1,139 +0,0 @@
# Software list
---
softwarelist:
- name: Aegisub
desc: Subtitle editor
url: http://www.aegisub.org/
img: aegisub.png
- name: Ansible
desc: Provisioning automation system
url: https://www.ansible.com/
img: ansible.png
- name: Ardour
desc: Digital audio workstation
url: http://ardour.org/
img: ardour.png
- name: Audacity
desc: Audio recorder and editor
url: http://web.audacityteam.org/
img: audacity.png
- name: Brasero
desc: Optical disk burning utility
url: https://wiki.gnome.org/Apps/Brasero
img: brasero.png
- name: DVDStyler
desc: DVD mastering tool
url: https://www.dvdstyler.org/en/
img: dvdstyler.png
- name: GIMP
desc: Image Manipulation Package
url: http://www.gimp.org/
img: gimp.png
- name: Inkscape
desc: 2D vector graphic editing application
url: http://www.inkscape.org/
img: inkscape.png
- name: Kdenlive
desc: Non-linear video editor
url: http://kdenlive.org/
img: kdenlive.png
- name: Krita
desc: Digital painting application
url: http://www.krita.org/
img: krita.png
- name: LibreOffice
desc: Office Suite
url: https://www.libreoffice.org
img: libreoffice.png
- name: MediaWiki
desc: Collaborative document editing platform
url: http://mediawiki.org/
img: mediawiki.png
- name: Mumble
desc: VOIP teleconferencing package
url: https://wiki.mumble.info/
img: mumble.png
- name: MyPaint
desc: Digital painting application
url: http://mypaint.org/about/
img: mypaint.png
- name: OBS Studio
desc: Screencasting package
url: https://obsproject.com/
img: obs.png
- name: Papagayo-NG
desc: Lipsinc animation editor
url: https://morevnaproject.org/papagayo-ng/
img: papagayo-ng.png
- name: RapidSVN
desc: Subversion (version control) client
url: https://rapidsvn.org/
img: rapidsvn.png
- name: RenderChan
desc: Render management system
url: https://morevnaproject.org/renderchan
img: renderchan.png
- name: Resource Space
desc: Digital asset management system
url: https://www.resourcespace.com/
img: resourcespace.png
- name: Subversion
desc: Version control system
url: https://subversion.apache.org/
img: subversion.png
- name: Synfig
desc: 2D animation package
url: http://synfig.org/
img: synfig.png
- name: TACTIC
desc: Digital asset and project management system
url: https://southpawtech.com/tactic-open-source/
img: tactic.png
- name: Trac
desc: Version control web interface (for Subversion)
url: https://trac.edgewall.org/
img: trac.png
- name: Ubuntu Studio
desc: Multimedia distribution of GNU/Linux
url: https://ubuntustudio.org/
img: ubuntustudio.png
- name: VLC
desc: Media player
url: https://www.videolan.org/index.html
img: vlc.png
- name: Vokoscreen
desc: Screencasting software
url: http://linuxecke.volkoh.de/vokoscreen/vokoscreen.html
img: vokoscreen.png
- name: Wordpress
desc: Content management system
url: https://wordpress.org/
img: wordpress.png

View File

@ -1,140 +0,0 @@
---
stylesheets:
- sponsorship
individual:
- name: Donation
amount: "Any"
gumroad_url: "https://gumroad.com/anansispace#ZCNlG"
patreon_url: "https://www.patreon.com/lunatics"
embed_template: paypal_donate_button
img: donations.png
description: >
If you just want to help us out, we can take simple donations of any amount
via our Gumroad store (once only), Patreon Memberships (multiple tiers
per-episode), or by making a one-time donation via PayPal.
- name: Patron
amount: "$20.00"
gumroad_url: "https://gumroad.com/anansispace#sumVF"
patreon_url: "https://www.patreon.com/lunatics"
img: patron_sponsor.png
description: >
Patron sponsors' names are listed at the end of the credits. You
may use a pseudonym, collective name, or business name if you like,
as long as there's no offensive language or messages included.
This is included with Patreon memberships of $20 per episode or more,
or can be acquired for one episode via our Gumroad account.
- name: Silver Sponsorship
amount: "$50.00"
gumroad_url: "https://gumroad.com/anansispace#sumVF"
patreon_url: "https://www.patreon.com/lunatics"
img: silver_sponsor.png
description: >
Silver sponsors get their names in a prominent listing after the
Gold sponsors.
- name: Gold Sponsorship
amount: "$100.00"
gumroad_url: "https://gumroad.com/anansispace#sumVF"
patreon_url: "https://www.patreon.com/lunatics"
img: gold_sponsor.png
description: >
Gold sponsors get their names in a prominent listing, after commercial
sponsorships, but before all other individual sponsorships. They will
also be listed in the credits on the download page, but they will not
be linked. You may use a company or collective name or a pseudonym rather
than your legal name, if you like. Please no foul language, slogans, or
political messages here, though.
- name: Film Freedom Monthly Subscription
amount: "$3+"
patreon_url: "https://www.patreon.com/filmfreedom"
img: filmfreedom_subscription.png
description: >
If you are mainly interested in our technical, development, and documentation
work, and like the predictability of a monthly subscription, please consider
supporting our <a href="http://filmfreedom.org">Film Freedom</a> project on
Patreon. We're starting a podcast to share our experiences with free culture
and free licenses software for production work, as well as sharing video and
written tutorials, research, and hints.
commercial:
- name: Commercial Sponsorship
amount: "$300.00"
gumroad_url: "https://gumroad.com/anansispace#chuEA"
email_address: sales@anansispaceworks.com
img: commercial_sponsor.png
description: >
Commercial sponsors get a space for a large monochrome logotype graphic
in the credits. They will appear in clustered groups alongside the credits,
rendered in the same color as the credits, and listed after the
"Commercial Logo" sponsorships (but before any of the individual sponsorships).
These logos will also be included in the credits list on the episode download
page on our website, and you may provide a URL to link the logo to from the
web page.
- name: Logo Commercial Sponsorship
amount: "$1000.00"
gumroad_url: "https://gumroad.com/anansispace#chuEA"
email_address: sales@anansispaceworks.com
img: logo_sponsor.png
description: >
Logo sponsors will get a square space beside or ahead of the end credits in the
episode, and a prominently-placed logo in the download page for the episode on our
website. You may provide a URL to link to from the logo for the website.
The logo art will appear at 480x480 px at our nominal 1920x1080 production frame,
although scaling to online video sites may make it appear smaller, so you should
plan accordingly (use a bold design and large enough font).
Your logo will typically appear alongside other logo sponsors in the credits. We
limit the number of possible logo spots to a maximum of 12.
corporate:
- name: Anorthosite Principal Episode Sponsorship
amount: "$25,000"
email_address: mailto:sales@anansispaceworks.com
img: anorthosite_sponsor.png
description: >
We estimate that it costs a minimum of $25,000 to produce an episode of "Lunatics!",
which of course, is very inexpensive by TV animation standards, but is enabled by our
low overhead, free-software pipeline, and virtual studio approach.
For this amount, we offer the maximum sponsorship exposure, with an animated logo
flown right at the beginning, prior even to our own "Anansi Spaceworks" production
logo. There will only be one such sponsor accepted for an episode, so the placement
is exclusive.
If you do not have a prepared logo, we can "fly" a simple logo for you, based
on a simple graphic trademark or corporate logo from you.
You will also get a prominent placement ahead of credits on our episode download
page, which can be linked to your company's website.
- name: Breccia Associate Episode Sponsorship
amount: "$10,000"
email_address: mailto:sales@anansispaceworks.com
img: breccia_sponsor.png
description: >
If a full episode sponsorship is a little too high, we also have an "Associate"
sponsorship for half the price, with only a slightly less prominent placement, after
our initial production logo, but still before the episode starts.
Obviously, this one is not exclusive, though we won't take more than three associate
sponsorships for an episode, or one with a full-episode sponsorship.
As with the episode sponsorship, you can provide us with a logo animation, or we
can do a simple animation for you, based on your logo art.
You will also get a prominent placement ahead of the credits on our episode download
page, which can be linked to your company's website.

View File

@ -1,28 +1,25 @@
# Episode release data # Episode release data
# See also series.yaml for documentation of options # See also series.yaml for documentation of options
--- ---
series: S1 series: LunaGen Intro
episode: 1 episode: 1
mode: production mode: production
title: "Prolog: 'No Children in Space'" title: "Yaml Tutorial | Learn YAML in 18 mins"
poster: s1e01-prolog-600sq.png poster: s1e01-yaml_tut_yt-nana-600sq.png
status: Finishing and Rendering Sequences. Coming Soon! status: YAML Intro From YouTube
stylesheets: stylesheets:
- bkg_earth_limb - bkg_earth_limb
description: > description: >
In the first episode of this hard-science-fiction fairytale, seven-year-old In lieu of a custom tutorial for LunaGen, this is a tutorial on YouTube
Georgiana Lerner becomes the first child in space, while her mother grapples for YAML syntax, presented by "TechWorld with Nana" I'm also testing
with press questions about the ethics of raising children in space. Both fly embedding a video from YouTube.
into orbit aboard a Soyuz launch vehicle from the same launchpad as Yuri
Gagarin took 79 years earlier, on the first leg of their journey to the Moon
to join the first true extra-terrestrial settlement.
videos: videos:
- id: preview - id: tutorial
name: Preview name: Tutorial
url: https://player.vimeo.com/video/350535112 url: https://www.youtube.com/watch?v=1uFVr15xDGg
btn: s1e01-preview-btn.png btn: s1e01-yaml_tut_yt-nana-60btn.png
product: product:
img: om_dvd.png img: om_dvd.png
@ -43,261 +40,22 @@ product:
sponsors: sponsors:
full_sponsor: full_sponsor: []
- name: Film Freedom Foundation
url: http://www.filmfreedom.org
img: film_freedom_foundation.png
logo_sponsors: logo_sponsors: []
- name: New Worlds Institute
url: https://earthlightfoundation.org/newworlds/
img: newworlds-600px.png
- name: Indian Pirate Party
url: http://pirates.org.in
img: indian_pirates-600px.png
- name: The Luna Project
url: http://www.lunarcc.org
img: luna_project-600px.png
corp_sponsors: [] corp_sponsors: []
gold_sponsors: [] gold_sponsors: []
silver_sponsors: silver_sponsors: []
- Chris Kuhn
patron_sponsors: patron_sponsors: []
- Tobias Platen
- Shiva Wolfe
- Filip Krška
- Morevna Project
- Nigel Waite
- Chris Kuhn
backer_sponsors: backer_sponsors: []
- Martin Ansdell-Smith
- Jim Bedford
- Mauro Bieg
- Ryan Cartwright
- John Colagioia
- Tom Curl
- Konstantin Dmitriev
- Jonathan Fluck
- Joe Futrelle
- Thomas Gideon
- Gal Goldschmidt
- Franz Gustav
- Janet Hancock
- Simon Harris
- Ian
- Javier
- Norman Jolley
- David Jordan
- Emmanouel Kapernaros
- Kathryn N Kapust
- Tom Kiesel
- Mike Linksvayer
- Raffaele Manzo
- David Maulik
- Donna & John Myers
- John Myers
- Stephen Ormsby
- Derek Pearcy
- Vibha Pingle
- Mike Riley
- Gregor B. Rosenauer
- Timo Rossi
- Karen Sandler
- Hugo Simões
- Elizabeth Small
- Barry Solow
- Junius Stone
- Julie Tribble
- John Tyler
- Hal Tynan
- Stuart Ward
- Robert Wicks
- Shiva Wolfe
- Joseph Yu
- mm2001
credits: credits:
main_credits: main_credits: []
-
- Screenplay
- Rosalyn Hunter
-
- Produced & Directed
- Terry Hancock
-
- Character Design
- Daniel Fu
cast_credits:
-
- Narrator
- Melodee M. Spevack
-
- Hiromi Lerner
- Karrie Shirou
-
- Georgiana Lerner
- Ariel Hancock
-
- Boy on Train
- Shamil Aminov
-
- Mother on Train
- Nadezhda Dmitrieva
-
- 'Reporter #1 (USA)'
- Terry Hancock
-
- 'Reporter #2 (Canada)'
- Jami Cullen
-
- 'Reporter #3 (Japan)'
- Miki Matsumoto
-
- Sergei Titov
- Sergei Oleinik
-
- Press Director
- Kristina Ponomarenko
-
- Pad Crew Woman
- Kristina Ponomarenko
-
- Pad Crew Man
- Terry Hancock
-
- Launch Controller
- Veronica Kurshinskaya
animation_credits:
char_models:
- Bela Szabo
- Keneisha Perry
- Andrew Pray
mech_models:
- Chris Kuhn
mech_rigs:
- Chris Kuhn
set_models:
- Sathish Kumar
- Travis Souza
- Johnathon Wilson
misc_models:
- Terry Hancock
- Andrew Pray
- Keneisha Perry
- Cosmin Planchon
- Vyacheslav Yastrebcev
- Guillaume Côte
- Gorka Mendieta
char_rigs:
- Keneisha Perry
char_animation:
- Keneisha Perry
graphics:
- Timothé Giet
- Paul Bourke
sound_credits:
sound_design:
- Terry Hancock
effects_sound_transit:
- Dmitry Urupin
- Fabian Klenk
- Acoustic Space Lab
- Leandros Ntounis
- Sonu Kapoor
- Gustavo Hernandez
effects_freesound:
- timlaroche
- Benboncan
- TinyJiro
- Razzvio
- stratcat322
- mansardian
- Kevinflo
- klankbeeld
- LG
- decembered
- ERH
- engreitz
effects_other:
- Wikipedia
- Alex Lep
- www.ljudo.com
- www.rutgermuller.nl
- Timm Seuss (Chernobyl Journal)
- NASA Videos
music_credits:
- title: Space Zine (Main Title Mix)
composer: 'Music & Lyrics: Elaine Walker'
artist: Zia
detail: 2006 (Martians), 2012 (TV Size Remix)
license: Relicensed to CC By-SA 4.0 by permission of the artist.
catalog: ziaspace.com
- title: Nylon
artist: JMF
catalog: "Direction Orient /Jamendo #8924"
license: 2008 JMF, CC By-SA 3.0
- title: Restless Heart
artist: Yunus
catalog: "Running Against Time /Jamendo #41619"
license: 2009 Yunus Barbaros Kuru, CC By-SA 2.0/DE
- title: Once Upon a Time
artist: A.K. 1974
catalog: "Orchestral Works / Jamendo #55503"
license: 2009 A.K. 1974, CC By-SA 3.0
- title: Rise of the Titans/Back to Adventure
artist: Butterfly Tea
catalog: "Adventure Action / Jamendo #36237"
license: 2008 Butterfly Tea, CC By-SA 2.0/FR
- title: Andoria Main Title
artist: Butterfly Tea
catalog: "Magical and Fantasy Musics / Jamendo #36315"
license: 2008 Butterfly Tea, CC By-SA 2.0/FR
- title: Orient
artist: Lulo
catalog: "Collage / Jamendo #49715"
license: 2009 Raúl Martín, CC By-SA 3.0
- title: Don't Lose Heart, We're Nearly Through
artist: Insignificance
catalog: "One Minute and Two / Jamendo #46114"
license: 2009 Insignificance, CC By-SA 3.0
software_credits:
- - Project Website Design
- Elsa Balderrama
- - Renderchan & Afanasy Rendering Workflow
- Konstantin Dmitriev
- Morevna Project
- - KitCAT Prototype Development
- Katrina Niolet
- - LunaGen and Release Site Design
- Terry Hancock
cast_credits: []

View File

@ -0,0 +1,24 @@
# Episode release data
# See also series.yaml for documentation of options
---
series: LunaGen Intro
episode: 1
mode: production
title: "Jinja2 - 101 - Intro to Jinja2 template building"
poster: s1e02-jinja2_tut-vimeo-Schulman-600sq.png
status: Jinja2 Tutorial from Vimeo
stylesheets:
- bkg_earth_limb
description: >
In lieu of a custom tutorial for LunaGen, this is a tutorial on Vimeo about
using Jinja2 templates, by Jeremy Schulman. Also testing embedding a video
from Vimeo.
videos:
- id: tutorial
name: Tutorial
url: https://vimeo.com/120005103
btn: s1e02-jinja2_tut-vimeo-Schulman-60btn.png

View File

@ -0,0 +1,22 @@
# Episode release data
# See also series.yaml for documentation of options
---
series: LunaGen Intro
episode: 1
mode: production
title: "A line-by-line breakdown of my website's cascading style sheet"
poster: s1e03-css_tut_pt-ChrisWere-600sq.png
status: YAML Intro From YouTube
stylesheets:
- bkg_earth_limb
description: >
In lieu of a custom tutorial for LunaGen, this is a tutorial on PeerTube
on CSS, by Chris Were Digital, so it's also testing PeerTube embedding.
videos:
- id: tutorial
name: Tutorial
url: https://peertube.tv/w/jEpwjYwiwEQyWsskzxJVxd
btn: s1e03-css_tut_pt-ChrisWere-60btn.png

View File

@ -1,7 +1,7 @@
# Definitions for episode series data # Definitions for episode series data
--- ---
serieslist: serieslist:
- name: Series 1 - name: LunaGen Intro
order: 1 order: 1
directory: S1 directory: S1
modes: modes:
@ -19,190 +19,4 @@ serieslist:
labels: ordered labels: ordered
template: centered_credits template: centered_credits
animation_credits:
order: 1
heading: "Modeling & Animation"
labels:
- - char_models
- "Character Modeling"
- - mech_models
- "Mechanical Modeling"
- - set_models
- "Set Modeling"
- - misc_models
- "Props & Additional Models"
- - mech_rigs
- "Mechanical Rigging"
- - char_rigs
- "Character Rigging"
- - char_animation
- "Character Animation"
- - textures
- "Textures & Decals"
- - graphics
- "2D Graphics"
template: basic_credits
cast_credits:
order: 2
labels: ordered
heading: "Cast"
template: cast_credits
sound_credits:
order: 3
heading: "Sound"
labels:
- - sound_design
- "Sound Design"
- - mixing
- "Mixing"
- - foley
- "Foley"
- - effects_sound_transit
- "Effects and Ambience from Sound Transit"
- - effects_freesound
- "Effects from FreeSound.org"
- - effects_other
- "Other Sounds"
- - effects
- "Sound Effects and Ambience"
template: basic_credits
music_credits:
order: 4
heading: "Music"
labels: ordered
template: music_credits
software_credits:
order: 5
labels: ordered
heading: "Software"
template: centered_credits
sponsortypes:
full_sponsor:
limit: 1
page: 1
excludes:
- half_sponsors
template: full_sponsor
desc: >
Our Episode Sponsor is the primary source of funding for an episode,
donating at least $25,000 for production, which pays for basic production
requirements for one episode (essentially ensures that the episode will get made).
Only one "Episode Sponsor" is possible on a single episode.
If your organization would like to be the primary sponsor for an entire
series ("season") of Lunatics!, we would be happy to package up to twelve
episode sponsorships as a single block at $300,000.
If you would like your company to become a Lunatics! episode sponsor
(or co-sponsor), please contact us at sponsorships@anansispaceworks.com
for legal details and electronic funds transfer information. And thank you
for considering us!
half_sponsors:
limit: 2
page: 2
excludes:
- full_sponsor
template: half_sponsors
desc: >
Episode Co-Sponsors contribute at least half of the funds needed to guarantee
an episode's production, or $10,000. This, in combination with a second
episode co-sponsor, episode sponsor, or matched with a number of smaller
sponsorships can also get us to the $25,000 we need to ensure production.
There may be up to two Episode Co-Sponsors on an episode.
logo_sponsors:
limit: 30
page: 3
template: logo_sponsors
desc: >
Our Corporate "Logo" Sponsorships are aimed at small business owners with
an interest in supporting the arts and marketing their brand. These sponsors
have contributed at least $1000 towards a episode's production. And of course,
they include the full-color square logos you see in our credits. This is the
largest sponsorship we sell through our Gumroad Store, but if you prefer to
save on transfer costs, you can also contact us at sponsorships@anansispaceworks.com
for EFT (bank transfer) details.
corp_sponsors:
limit: 100
page: 9
template: corp_sponsors
desc: >
Our Corporate Sponsorships are our basic commercial sponsorship level, and
include a monochrome title or brand trademark/logotype for your company.
These sponsors have contributed at least $300 towards an episode's production.
gold_sponsors:
limit: 5000
page: 120
template: gold_sponsors
desc: >
Gold Sponsorships are targeted at individuals who want to fund our project
and receive a much more prominent credit than Patron or Backer credits. They
have contributed at least $100 towards an episode's production.
silver_sponsors:
limit: 5000
page: 120
template: silver_sponsors
desc: >
Silver Sponsorships are targeted at individual who want to fund our project
and recive a more prominent credit than Patron or Backer credits. They have
contributed at least $50 towards an episode's production.
patron_sponsors:
limit: 10000
template: patron_sponsors
desc: >
Patrons have contributed at least $20 towards an episode's production, either
through a one-time donation via Gumroad or via a subscription to our Patreon
account.
backer_sponsors:
limit: 5000
template: backer_sponsors
desc: >
If not funded through other means, we will arrange a crowdfund to try to
raise the base funding to start on an episode (about $7500). If you are one
of the backers on such a crowdfund (and haven't requested to be anonymous),
you'll find your name listed here.
- name: Audiodrama
order: 100 # Always listed after the video series
directory: A1
modes:
teaser:
template: audiodrama_teaser
release:
template: audiodrama_release
credits:
main_credits:
heading: None
labels: ordered
template: centered_credits
cast_credits:
heading: None
labels: ordered
template: cast_credits
sound_credits:
heading: Sound Design & Effects
labels: ordered
template: basic_credits
music_credits:
heading: Music
labels: ordered
template: music_credits
sponsortypes:
backer_sponsors:
template: backer_sponsors
patron_sponsors:
template: patron_sponsors

BIN
LunaGen/testdata/series/imgsrc/DanaeMillerClendon-SilverStripeYAML.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/JeremySchulman-288sq.webp (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/JeremySchulman-Jinja2-Vimeo.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/JoeShindelar-YAML_lesson1.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/TechWorld-Nana.jpg (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/TechWorldNana-YAML_intro.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/TechWorld_Nana_Banner.jpg (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/YAML_Tut_Nana_sq.jpg (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/YAML_Tut_Nana_sq.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/YAML_Tut_Nana_thumbnail.jpg (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/css_ChrisWereDigital-2.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/css_intro-YT-EJMedia.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

BIN
LunaGen/testdata/series/imgsrc/css_linebyline-ChrisWereDigital.png (Stored with Git LFS) vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -100,5 +100,15 @@ class Test_Lunagen_CLI_Function(unittest.TestCase, LooksLikeHelper, HTMLTidyHelp
self.assertHTMLTidy(index_path) self.assertHTMLTidy(index_path)
self.assertFileMatches(index_path, 'products_index.html') self.assertFileMatches(index_path, 'products_index.html')
def test_series_example(self):
subprocess.run(('lunagen',
'series', 'build/series_site', '--verbose', '--seed=0'),
env={'PATH':self.cwd})
index_path = os.path.join(os.path.dirname(__file__), '..', 'testdata',
'build', 'series_site', 'index_html')
self.assertTrue(os.path.exists(index_path))
self.assertHTMLTidy(index_path)
self.assertFileMatches(index_path, 'series_index.html')