Switch help generation system to use Genshi templates

This commit is contained in:
Kovid Goyal 2008-03-02 19:57:11 +00:00
parent a9fdbb7bc2
commit c9e9bf2d68
18 changed files with 406 additions and 473 deletions

View File

@ -1 +0,0 @@
<b>libprs500</b> is an ebook management application with support for various ebook readers. Created by <b>Kovid Goyal</b> &copy; 2007.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1,109 +0,0 @@
<?xml version='1.0' encoding='UTF-8'?>
<QtHelpProject version="1.0">
<namespace>libprs500</namespace>
<virtualFolder>manual</virtualFolder>
<customFilter name="index">
<filterAttribute>libprs500</filterAttribute>
</customFilter>
<filterSection>
<filterAttribute>libprs500</filterAttribute>
<toc>
<section ref="start.html" title="Start" />
<section ref="gui.html" title="Graphical User Interface">
<section ref="gui.html#actions" title="Actions" />
<section ref="gui.html#catalogs" title="Catalogs" />
<section ref="gui.html#search_sort" title="Search &amp; Sort" />
<section ref="gui.html#configuration" title="Configuration" />
<section ref="gui.html#book_details" title="Book Details" />
<section ref="gui.html#jobs" title="Jobs" />
</section>
<section ref="cli-index.html" title="Command Line Interface">
<section ref="cli-isbndb.html" title="isbndb" />
<section ref="cli-pdfreflow.html" title="pdfreflow" />
<section ref="cli-mobi2lrf.html" title="mobi2lrf" />
<section ref="cli-lrf-meta.html" title="lrf-meta" />
<section ref="cli-lit2lrf.html" title="lit2lrf" />
<section ref="cli-lrf2lrs.html" title="lrf2lrs" />
<section ref="cli-index.html" title="index" />
<section ref="cli-web2lrf.html" title="web2lrf" />
<section ref="cli-lrs2lrf.html" title="lrs2lrf" />
<section ref="cli-txt2lrf.html" title="txt2lrf" />
<section ref="cli-web2disk.html" title="web2disk" />
<section ref="cli-opf-meta.html" title="opf-meta" />
<section ref="cli-html2lrf.html" title="html2lrf" />
<section ref="cli-rtf2lrf.html" title="rtf2lrf" />
<section ref="cli-librarything.html" title="librarything" />
<section ref="cli-epub2lrf.html" title="epub2lrf" />
<section ref="cli-rtf-meta.html" title="rtf-meta" />
<section ref="cli-pdf2lrf.html" title="pdf2lrf" />
<section ref="cli-lrf2html.html" title="lrf2html" />
<section ref="cli-any2lrf.html" title="any2lrf" />
<section ref="cli-mobi2oeb.html" title="mobi2oeb" />
</section>
<section ref="faq.html" title="Frequently Asked Questions">
<section ref="faq.html#Whatdevicesdoeslibprs500support" title="What devices does libprs500 support?" />
<section ref="faq.html#Whatformatsdoeslibprs500readmetadatafrom" title="What formats does libprs500 read metadata from?" />
<section ref="faq.html#Whatformatsdoeslibprs500supportconversiontofrom" title="What formats does libprs500 support conversion to/from?" />
<section ref="faq.html#WhatarethebestformatstoconverttoLRF" title="What are the best formats to convert to LRF?" />
<section ref="faq.html#WhydoesthePDFconversionlosesomeimages" title="Why does the PDF conversion lose some images?" />
<section ref="faq.html#Wherearethebookfilesstored" title="Where are the book files stored?" />
<section ref="faq.html#CanIsavemybookstothedisk" title="Can I save my books to the disk?" />
<section ref="faq.html#Iusedlibprs500totransfersomebookstomyreaderandnowtheSONYsoftwarehangseverytimeIconnectthereader" title="I used libprs500 to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?" />
<section ref="faq.html#NoimagesintheLRFfileafterconversionfromHTML" title="No images in the LRF file after conversion from HTML?" />
<section ref="faq.html#CanIuseweb2lrftodownloadanarbitrarywebsite" title="Can I use web2lrf to download an arbitrary website?" />
<section ref="faq.html#Iwantsomefeatureaddedtolibprs500.WhatcanIdo" title="I want some feature added to libprs500. What can I do?" />
<section ref="faq.html#HowdoIusesomeoftheadvancedfeaturesoftheconversiontools" title="How do I use some of the advanced features of the conversion tools?" />
</section>
</toc>
<files>
<file>cli-isbndb.html</file>
<file>cli-pdfreflow.html</file>
<file>cli-mobi2lrf.html</file>
<file>cli-lrf-meta.html</file>
<file>cli-lit2lrf.html</file>
<file>faq.html</file>
<file>cli-lrf2lrs.html</file>
<file>cli-index.html</file>
<file>cli-web2lrf.html</file>
<file>cli-lrs2lrf.html</file>
<file>cli-txt2lrf.html</file>
<file>start.html</file>
<file>cli-web2disk.html</file>
<file>gui.html</file>
<file>cli-opf-meta.html</file>
<file>cli-html2lrf.html</file>
<file>cli-rtf2lrf.html</file>
<file>cli-librarything.html</file>
<file>cli-epub2lrf.html</file>
<file>cli-rtf-meta.html</file>
<file>cli-pdf2lrf.html</file>
<file>cli-lrf2html.html</file>
<file>cli-any2lrf.html</file>
<file>cli-mobi2oeb.html</file>
<file>styles/common.css</file>
<file>images/edit_meta_information.png</file>
<file>images/remove_books.png</file>
<file>images/book_details.png</file>
<file>images/search_sort.png</file>
<file>images/search_button.png</file>
<file>images/convert_ebooks.png</file>
<file>images/add_books.png</file>
<file>images/save_to_disk.png</file>
<file>images/actions.png</file>
<file>images/catalogs.png</file>
<file>images/valid.png</file>
<file>images/jobs.png</file>
<file>images/send_to_device.png</file>
<file>images/configuration.png</file>
<file>images/search.png</file>
<file>images/news.png</file>
<file>images/view.png</file>
<file>images/fetch_news.png</file>
<file>images/cli.png</file>
</files>
</filterSection>
</QtHelpProject>

View File

@ -1,35 +0,0 @@
<!DOCTYPE webproject>
<webproject>
<project type="Local" name="libprs500" encoding="utf8" >
<upload/>
<author/>
<email/>
<defaultDTD>-//W3C//DTD XHTML 1.1//EN</defaultDTD>
<item url="about.txt" uploadstatus="1" />
<item url="libprs500.qhcp" uploadstatus="1" />
<item url="libprs500.qhp" uploadstatus="1" />
<item url="Makefile" uploadstatus="1" />
<item url="" uploadstatus="1" />
<annotations/>
<templates>templates/</templates>
<toolbars>toolbars/</toolbars>
<item url="templates/" uploadstatus="1" />
<item url="templates/basic.html" uploadstatus="1" />
<item url="index.html" uploadstatus="1" />
<item url="common.css" uploadstatus="1" />
<item url="gui.html" uploadstatus="1" />
<item url="images/" uploadstatus="1" />
<item url="images/actions.png" uploadstatus="1" />
<item url="images/book_details.png" uploadstatus="1" />
<item url="images/catalogs.png" uploadstatus="1" />
<item url="images/configuration.png" uploadstatus="1" />
<item url="images/jobs.png" uploadstatus="1" />
<item url="images/library.png" uploadstatus="1" />
<item url="images/search.png" uploadstatus="1" />
<item url="libprs500.session" uploadstatus="1" />
<item url="libprs500.webprj" uploadstatus="1" />
<item url="templates/navtree.html" />
<item url="start.html" />
<item url="faq.html" />
</project>
</webproject>

View File

@ -17,13 +17,29 @@
import sys, glob, mechanize, time, subprocess, os, shutil, re
from tempfile import NamedTemporaryFile
from xml.etree.ElementTree import parse, tostring, fromstring
from genshi.template import TemplateLoader, MarkupTemplate
if not os.path.exists('build'):
os.mkdir('build')
# Load libprs500 from source copy
sys.path.insert(1, os.path.dirname(os.path.dirname(os.getcwdu())))
from libprs500.ebooks.BeautifulSoup import BeautifulSoup
from libprs500.linux import entry_points
from libprs500 import __appname__, __author__, __version__
class Template(MarkupTemplate):
def generate(self, *args, **kwargs):
kwdargs = dict(app=__appname__, author=__author__.partition('<')[0].strip(),
version=__version__, footer=True)
kwdargs.update(kwargs)
return MarkupTemplate.generate(self, *args, **kwdargs)
loader = TemplateLoader(os.path.abspath('templates'), auto_reload=True,
variable_lookup='strict', default_class=Template)
def browser():
opener = mechanize.Browser()
@ -32,31 +48,11 @@ def browser():
opener.addheaders = [('User-agent', 'Mozilla/5.0 (X11; U; i686 Linux; en_US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4')]
return opener
def update_manifest(src):
root = fromstring(src)
files = root.find('filterSection').find('files')
attrs = files.attrib.copy()
files.clear()
files.attrib = attrs
files.text = '\n%12s'%' '
files.tail = '\n%4s'%' '
for f in glob.glob('*.html')+glob.glob('styles/*.css')+glob.glob('images/*'):
if f.startswith('preview') or f in ('navtree.html', 'index.html'):
continue
el = fromstring('<file>%s</file>'%f)
el.tail = '\n%12s'%' '
files.append(el)
el.tail = '\n%8s'%' '
return tostring(root, 'UTF-8').decode('UTF-8')
def validate(file=None):
br = browser()
files = [file] if file is not None else glob.glob('*.html')
files = [file] if file is not None else glob.glob('build/*.html')
for f in files:
if f.startswith('preview-'):
if f.endswith('navtree.html'):
continue
print 'Validating', f
raw = open(f).read()
@ -74,14 +70,7 @@ def validate(file=None):
return
def clean():
for pat in ('preview-*.html', '*.qhc', '*.qch', 'cli-*.html', '~/.assistant/libprs500*'):
for f in glob.glob(pat):
f = os.path.abspath(os.path.expanduser(f))
if os.path.exists(f):
if os.path.isdir(f):
shutil.rmtree(f)
else:
os.unlink(f)
shutil.rmtree('build')
return 0
def compile_help():
@ -91,92 +80,53 @@ def compile_help():
QCG = os.path.join(QTBIN, 'qcollectiongenerator')
QTA = os.path.join(QTBIN, 'assistant')
os.environ['LD_LIBRARY_PATH'] = QTLIB
for f in ('libprs500.qch', 'libprs500.qhc'):
for f in ('build/%s.qch'%__appname__, 'build/%s.qhc'%__appname__):
if os.path.exists(f):
os.unlink(f)
subprocess.check_call((QCG, 'libprs500.qhcp'))
subprocess.call((QTA, '-collectionFile', 'libprs500.qhc'))
cwd = os.getcwd()
os.chdir('build')
try:
subprocess.check_call((QCG, __appname__+'.qhcp', '-o', __appname__+'.qhc'))
subprocess.call((QTA, '-collectionFile', __appname__+'.qhc'))
finally:
os.chdir(cwd)
def populate_section(secref, items, src):
root = fromstring(src)
toc = root.find('filterSection').find('toc')
sec = None
if secref is None:
sec = toc
ss = '\n%8s'%' '
ls = '\n%12s'%' '
else:
for c in toc.findall('section'):
if c.attrib['ref'] == secref:
sec = c
break
ss = '\n%12s'%' '
ls = '\n%16s'%' '
attr = sec.attrib.copy()
tail = sec.tail
sec.clear()
sec.attrib = attr
sec.tail = tail
sec.text = ls
secs = ['<section ref="%s" title="%s" />\n'%i for i in items]
sec.tail = ss
for i in secs:
el = fromstring(i)
sec.append(el)
el.tail = ss if i is secs[-1] else ls
raw = tostring(root, 'UTF-8')
return raw.decode('UTF-8')
def populate_faq(src):
soup = BeautifulSoup(open('faq.html').read().decode('UTF-8'))
items = []
toc = soup.find('div', id="toc")
for a in toc('a', href=True):
items.append(('faq.html%s'%a['href'], a.string))
return populate_section('faq.html', items, src=src)
def populate_cli(src):
cmds = []
for f in glob.glob('cli-*.html'):
cmds.append(f[4:].rpartition('.')[0])
items = [('cli-%s.html'%i, i) for i in cmds]
return populate_section('cli-index.html', items, src)
def populate_toc(src):
soup = BeautifulSoup(open('start.html', 'rb').read().decode('UTF-8'))
sections = [('start.html', 'Start')]
for a in soup.find(id='toc').findAll('a'):
sections.append((a['href'], a.string))
return populate_section(None, sections, src)
def populate_gui(src):
soup = BeautifulSoup(open('gui.html', 'rb').read().decode('UTF-8'))
sections = []
for a in soup.find(id='toc').findAll('a'):
sections.append(('gui.html'+a['href'], a.string))
return populate_section('gui.html', sections, src)
def get_subsections(section, level=0, max_level=1, prefix='templates'):
src = os.path.join(prefix, section)
if not os.path.exists(src):
return []
soup = BeautifulSoup(open(src, 'rb').read().decode('UTF-8'))
toc = soup.find(id='toc')
if toc is None:
return []
return [dict(href=section+a['href'] if a['href'].startswith('#') else a['href'],
title=a.string.replace('&amp;', '&'),
subsections=get_subsections(a['href'], level=1,
prefix=prefix, max_level=max_level) if level<max_level else [])\
for a in toc.findAll('a', href=True)]
def qhp():
src = open('libprs500.qhp', 'rb').read().decode('UTf-8')
src = update_manifest(src)
src = populate_toc(src)
src = populate_gui(src)
src = populate_faq(src)
src = populate_cli(src)
render()
cli_docs()
root = fromstring(src)
root.find('filterSection').find('toc')[-1].tail = '\n%8s'%' '
root.find('filterSection').find('toc').tail = '\n\n%8s'%' '
toc = get_subsections('start.html', prefix='build')
toc.insert(0, dict(title='Start', href='start.html', subsections=[]))
files = []
for loc in ('*.html', 'images'+os.sep+'*', 'styles'+os.sep+'*'):
files += glob.glob(os.path.join('build', loc))
files = [i.partition(os.sep)[2] for i in files]
open('libprs500.qhp', 'wb').write(tostring(root, encoding='UTF-8'))
tpl = loader.load('app.qhp')
raw = tpl.generate(toc=toc, files=files).render('xml')
open(os.path.join('build', __appname__+'.qhp'), 'wb').write(raw)
tpl = loader.load('app.qhcp')
open(os.path.join('build', __appname__+'.qhcp'), 'wb').write(tpl.generate().render('xml'))
about = open('templates'+os.sep+'about.txt', 'rb').read()
about = re.sub(r'\$\{app\}', __appname__, about)
about = re.sub(r'\$\{author\}', __author__.partition('<')[0].strip(), about)
open('build'+os.sep+'about.txt', 'wb').write(about)
compile_help()
def cli_docs():
@ -195,105 +145,60 @@ def cli_docs():
documented_cmds.sort(cmp=lambda x, y: cmp(x[0], y[0]))
undocumented_cmds.sort()
def sanitize_text(txt):
return txt.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
for cmd, parser in documented_cmds:
output = open('cli-%s.html'%cmd, 'wb')
template = open('templates/basic.html', 'rb').read().decode('utf-8')
template = re.sub('<title>\s*</title>', '<title>%s</title>'%cmd, template)
usage = [sanitize_text(i) for i in parser.usage.replace('%prog', cmd).splitlines(True) if i]
usage[0] = '<pre class="runcmd">%s</pre>'%usage[0]
usage[1:] = [i.replace(cmd, '<span class="cmd">%s</span>'%cmd) for i in usage[1:]]
usage = ''.join(usage).replace('\n', '<br />')
body = ('\n<h1 class="documentHeading">%s</h1>\n'%cmd)+'<div>\n%s\n</div>'%usage
groups = {}
for grp in parser.option_groups:
groups[(grp.title, grp.description)] = grp.option_list
def group_html(title, description, option_list):
res = []
if title is not None:
res.append('<tr><th colspan="2"><h3 class="subsectionHeading">%s</h3></th></tr>'%title)
if description is not None:
res.append('<tr><td colspan="2">%s<br />&nbsp;</td></tr>'%sanitize_text(description))
for opt in option_list:
shf = ' '.join(opt._short_opts)
lgf = opt.get_opt_string()
name = '%s<br />%s'%(lgf, shf)
help = sanitize_text(opt.help) if opt.help else ''
res.append('<tr><td class="option">%s</td><td>%s</td></tr>'%(name, help))
return '\n%8s'%' ' + ('\n%8s'%' ').join(res)
gh = [group_html(None, None, parser.option_list)]
for title, desc in groups.keys():
olist = groups[(title, desc)]
gh.append(group_html(title, desc, olist))
if ''.join(gh).strip():
body += '\n <h2 class="sectionHeading">[options]</h2>\n'
body += '\n <table class="option_table">\n%s\n </table>\n'%'\n'.join(gh)
output.write(template.replace('%body', body))
uc_html = '\n<ul class="cmdlist">\n%s</ul>\n'%'\n'.join(\
'<li>%s</li>\n'%i for i in undocumented_cmds)
dc_html = '\n<ul class="cmdlist">\n%s</ul>\n'%'\n'.join(\
'<li><a href="cli-%s.html">%s</a></li>\n'%(i[0], i[0]) for i in documented_cmds)
template = loader.load('cli-cmd.html')
open('build/cli-%s.html'%cmd, 'wb').write(
template.generate(cmd=cmd, parser=parser).render(doctype='xhtml'))
body = '<h1 class="documentHeading">The Command Line Interface</h1>\n'
body += '<div style="text-align:center"><img src="images/cli.png" alt="CLI" /></div>'
body += '<p>%s</p>\n'%'<b class="cmd">libprs500</b> has a very comprehensive command line interface to perform most operations that can be performed by the GUI.'
body += '<h2 class="sectionHeading">Documented commands</h2>\n'+dc_html
body += '<h2 class="sectionHeading">Undocumented commands</h2>\n'+uc_html
body += '<p>You can see usage for undocumented commands by executing them without arguments in a terminal</p>'
documented = [i[0] for i in documented_cmds]
template = loader.load('cli-index.html')
template = open('templates/basic.html', 'rb').read().decode('utf-8')
template = re.sub('<title>\s*</title>', '<title>%s</title>'%'Command Line Interface', template)
open('cli-index.html', 'wb').write(template.replace('%body', body))
open('build/cli-index.html', 'wb').write(
template.generate(documented=documented, undocumented=undocumented_cmds).render(doctype='xhtml'))
def html(src='libprs500.qhp'):
root = parse(src).getroot()
toc = root.find('filterSection').find('toc')
def is_leaf(sec):
return not sec.findall('section')
def process_branch(branch, toplevel=False):
parent = []
for sec in branch.findall('section'):
title = re.sub('&(?!amp;)', '&amp;', sec.attrib['title'])
html = '<li class="||||">\n<a target="content" href="%s">%s</a>\n</li>\n'%(sec.attrib['ref'], title)
lc = 'toplevel' if toplevel else 'nottoplevel'
html=html.replace('||||', '%s ||||'%lc)
def html():
toc = get_subsections('start.html', prefix='build')
toc.insert(0, dict(title='Start', href='start.html', subsections=[]))
template = loader.load('navtree.html')
dt = ('html', "-//W3C//DTD HTML 4.01 Transitional//EN",
"http://www.w3.org/TR/html4/loose.dtd")
raw = template.generate(footer=False, toc=toc).render(doctype=dt)
raw = re.sub(r'<html[^<>]+>', '<html lang="en">', raw)
open('build'+os.sep+'navtree.html', 'wb').write(raw)
type = 'file'
if not is_leaf(sec):
html = html.replace('</li>','%s\n</li>'%process_branch(sec))
type = 'folder'
parent.append(html.replace('||||', type))
html = '\n'.join(parent)
if toplevel:
return html
return '<ul>\n%s\n</ul>'%html
tree = process_branch(toc, True)
def render():
for d in ('images', 'styles'):
tgt = os.path.join('build', d)
if not os.path.exists(tgt):
os.mkdir(tgt)
for f in glob.glob(d+os.sep+'*'):
if os.path.isfile(f):
ftgt = os.path.join(tgt, os.path.basename(f))
if os.path.exists(ftgt):
os.unlink(ftgt)
os.link(f, ftgt)
template = open('templates/navtree.html').read()
open('navtree.html', 'wb').write(template.replace('%tree', tree)+'\n')
sections = [i['href'] for i in get_subsections('start.html')]
sections.remove('cli-index.html')
for f in sections + ['index.html', 'start.html']:
kwdargs = {}
if not isinstance(f, basestring):
f, kwdargs = f
dt = f.rpartition('.')[-1]
if dt == 'html':
dt = 'xhtml'
if f == 'index.html':
dt=('html', '-//W3C//DTD XHTML 1.0 Frameset//EN', 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd')
raw = loader.load(f).generate(**kwdargs).render(doctype=dt)
open(os.path.join('build', f), 'wb').write(raw)
def all(opts):
clean()
cli_docs()
qhp()
html()
if opts.validate:
validate()

View File

@ -0,0 +1 @@
<b>${app}</b> is an ebook management application with support for various ebook readers. Created by <b>${author}</b> &copy; 2007.

View File

@ -1,29 +1,29 @@
<?xml version="1.0" encoding="utf-8" ?>
<QHelpCollectionProject version="1.0">
<QHelpCollectionProject version="1.0" xmlns:py="http://genshi.edgewall.org/">
<assistant>
<title>libprs500 Help</title>
<startPage>qthelp://libprs500/manual/start.html</startPage>
<applicationIcon>../gui2/images/library.png</applicationIcon>
<title>${app} User Manual</title>
<startPage>qthelp://${app}/manual/start.html</startPage>
<applicationIcon>../../gui2/images/library.png</applicationIcon>
<enableFilterFunctionality>false</enableFilterFunctionality>
<enableDocumentationManager>false</enableDocumentationManager>
<enableAddressBar visible="true">true</enableAddressBar>
<aboutMenuText>
<text>About libprs500</text>
<text>About ${app}</text>
</aboutMenuText>
<aboutDialog>
<file>about.txt</file>
<icon>../gui2/images/dialog_information.svg</icon>
<icon>../../gui2/images/dialog_information.svg</icon>
</aboutDialog>
</assistant>
<docFiles>
<generate>
<file>
<input>libprs500.qhp</input>
<output>libprs500.qch</output>
<input>${app}.qhp</input>
<output>${app}.qch</output>
</file>
</generate>
<register>
<file>libprs500.qch</file>
<file>${app}.qch</file>
</register>
</docFiles>
</QHelpCollectionProject>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<QtHelpProject version="1.0"
xmlns:py="http://genshi.edgewall.org/"
>
<namespace>${app}</namespace>
<virtualFolder>manual</virtualFolder>
<filterSection>
<toc>
<py:for each="section in toc">
<section ref="${section['href']}" title="${section['title']}">
<py:for each="ss in section['subsections']">
<section ref="${ss['title']}" title="${ss['title']}" />
</py:for>
</section>
</py:for>
</toc>
<files>
<py:for each="file in files">
<file>${file}</file>
</py:for>
</files>
</filterSection>
</QtHelpProject>

View File

@ -0,0 +1,47 @@
<?python
from genshi import HTML
title = cmd
usage = [i for i in parser.usage.replace('%prog', cmd).splitlines(True) if i]
cmdline = usage[0]
usage = usage[1:]
usage = [i.replace(cmd, '<span class="cmd">%s</span>'%cmd) for i in usage]
groups = [(None, None, parser.option_list)]
for grp in parser.option_groups:
groups.append((grp.title, grp.description, grp.option_list))
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<title>${cmd}</title>
</head>
<body>
<pre class="runcmd">${cmdline}</pre>
<p>
<py:for each="line in usage">${HTML(line)}<br /></py:for>
</p>
<h2 class="sectionHeading">[options]</h2>
<table class="option_table">
<py:for each="title, desc, options in groups">
<tr py:if="title is not None"><th colspan="2"><h3 class="subsectionHeading">${title}</h3></th></tr>
<tr py:if="desc is not None"><td colspan="2">${desc}<br />&nbsp;</td></tr>
<tr py:for="option in options">
<td class="option" py:with="short = ', '.join(option._short_opts)">
${option.get_opt_string()}<br />${short}
</td>
<td py:with="help = option.help if option.help else ''">${help}</td>
</tr>
</py:for>
</table>
</body>
</html>

View File

@ -0,0 +1,38 @@
<?python
title="Command Line Interface"
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<title>${title}</title>
</head>
<body>
<div style="text-align:center"><img src="images/cli.png" alt="CLI" /></div>
<p>
<b class="cmd">${app}</b> has a very comprehensive command line
interface to perform most operations that can be performed by the GUI.
</p>
<h2 class="sectionHeading">Documented commands</h2>
<ul class="cmdlist" id="toc">
<li py:for="item in documented">
<a href="cli-${item}.html">${item}</a>
</li>
</ul>
<h2 class="sectionHeading">Undocumented commands</h2>
<ul class="cmdlist">
<li py:for="item in undocumented">${item}</li>
</ul>
<p>You can see usage for undocumented commands by executing them without arguments in a terminal</p>
</body>
</html>

View File

@ -1,14 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
<?python
title = 'Frequently Asked Questions'
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<meta name="author" content="Kovid Goyal" />
<meta name="copyright" content="&copy; 2008 Kovid Goyal" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Frequently Asked Questions</title>
<link rel="stylesheet" type="text/css" href="styles/common.css" />
<title>${title}</title>
<style type="text/css">
h2 {
font-family: monospace;
@ -17,38 +21,36 @@
</head>
<body>
<h1 class="documentHeading" id="FrequentlyAskedQuestions">Frequently Asked Questions</h1>
<div class="toc" id="toc">
<ul>
<li><a href="#Whatdevicesdoeslibprs500support">What devices does libprs500 support?</a></li>
<li><a href="#Whatformatsdoeslibprs500readmetadatafrom">What formats does libprs500 read metadata from?</a></li>
<li><a href="#Whatformatsdoeslibprs500supportconversiontofrom">What formats does libprs500 support conversion to/from?</a></li>
<li><a href="#Whatdevicesdoes${app}support">What devices does ${app} support?</a></li>
<li><a href="#Whatformatsdoes${app}readmetadatafrom">What formats does ${app} read metadata from?</a></li>
<li><a href="#Whatformatsdoes${app}supportconversiontofrom">What formats does ${app} support conversion to/from?</a></li>
<li><a href="#WhatarethebestformatstoconverttoLRF">What are the best formats to convert to LRF?</a></li>
<li><a href="#WhydoesthePDFconversionlosesomeimages">Why does the PDF conversion lose some images?</a></li>
<li><a href="#Wherearethebookfilesstored">Where are the book files stored?</a></li>
<li><a href="#CanIsavemybookstothedisk">Can I save my books to the disk?</a></li>
<li><a href="#Iusedlibprs500totransfersomebookstomyreaderandnowtheSONYsoftwarehangseverytimeIconnectthereader">I used libprs500 to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?</a></li>
<li><a href="#Iused${app}totransfersomebookstomyreaderandnowtheSONYsoftwarehangseverytimeIconnectthereader">I used ${app} to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?</a></li>
<li><a href="#NoimagesintheLRFfileafterconversionfromHTML">No images in the LRF file after conversion from HTML?</a></li>
<li><a href="#CanIuseweb2lrftodownloadanarbitrarywebsite">Can I use web2lrf to download an arbitrary website?</a></li>
<li><a href="#Iwantsomefeatureaddedtolibprs500.WhatcanIdo">I want some feature added to libprs500. What can I do?</a></li>
<li><a href="#Iwantsomefeatureaddedto${app}.WhatcanIdo">I want some feature added to ${app}. What can I do?</a></li>
<li><a href="#HowdoIusesomeoftheadvancedfeaturesoftheconversiontools">How do I use some of the advanced features of the conversion tools?</a></li>
</ul>
</div>
<h2 id="Whatdevicesdoeslibprs500support">What devices does libprs500 support?</h2>
<h2 id="Whatdevicesdoes${app}support">What devices does ${app} support?</h2>
<p>
At the moment libprs500 has full support for the SONY PRS500 and PRS505. However, using the "save to disk" function you can use it with any ebook reader that exports itself as a USB disk.
At the moment ${app} has full support for the SONY PRS500 and PRS505. However, using the "save to disk" function you can use it with any ebook reader that exports itself as a USB disk.
</p>
<h2 id="Whatformatsdoeslibprs500readmetadatafrom">What formats does libprs500 read metadata from?</h2>
<h2 id="Whatformatsdoes${app}readmetadatafrom">What formats does ${app} read metadata from?</h2>
<p>
libprs500 reads metadata from the following formats: LRF, PDF, LIT, RTF, OPF, MOBI, PRC, EPUB.
${app} reads metadata from the following formats: LRF, PDF, LIT, RTF, OPF, MOBI, PRC, EPUB.
In addition it can write metadata to: LRF, RTF, OPF
</p>
<h2 id="Whatformatsdoeslibprs500supportconversiontofrom">What formats does libprs500 support conversion to/from?</h2>
<h2 id="Whatformatsdoes${app}supportconversiontofrom">What formats does ${app} support conversion to/from?</h2>
<p>
libprs500 supports the conversion of the following formats to LRF: HTML, LIT, MOBI, PRC, EPUB, RTF, TXT, PDF and LRS. It also supports the conversion of LRF to LRS and HTML(upcoming). Note that libprs500 does not support the conversion of DRMed ebooks.
${app} supports the conversion of the following formats to LRF: HTML, LIT, MOBI, PRC, EPUB, RTF, TXT, PDF and LRS. It also supports the conversion of LRF to LRS and HTML(upcoming). Note that ${app} does not support the conversion of DRMed ebooks.
</p>
<h2 id="WhatarethebestformatstoconverttoLRF">What are the best formats to convert to LRF?</h2>
<p>
@ -66,9 +68,9 @@
<p>
You can save your books to the disk by selecting the books and clicking the "Save to disk" button. Your books will be saved in nicely organized folders.
</p>
<h2 id="Iusedlibprs500totransfersomebookstomyreaderandnowtheSONYsoftwarehangseverytimeIconnectthereader">I used libprs500 to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?</h2>
<h2 id="Iused${app}totransfersomebookstomyreaderandnowtheSONYsoftwarehangseverytimeIconnectthereader">I used ${app} to transfer some books to my reader, and now the SONY software hangs every time I connect the reader?</h2>
<p>
You should not use both libprs500 and Connect to transfer books to the reader. You can fix this problem by:
You should not use both ${app} and Connect to transfer books to the reader. You can fix this problem by:
</p>
<ul><li>Removing any storage cards from your reader.
</li><li>Deleting the file media.xml from the reader's main memory using windows explorer (search for the file to find all locations where it is present). Note that by doing this you will lose all your collections, bookmarks, history etc.
@ -82,15 +84,15 @@
<h2 id="CanIuseweb2lrftodownloadanarbitrarywebsite">Can I use web2lrf to download an arbitrary website?</h2>
<pre class="showcmd">web2lrf --url http://mywebsite.com default</pre>
<h2 id="Iwantsomefeatureaddedtolibprs500.WhatcanIdo">I want some feature added to libprs500. What can I do?</h2>
<h2 id="Iwantsomefeatureaddedto${app}.WhatcanIdo">I want some feature added to ${app}. What can I do?</h2>
<p>
You have two choices:
</p>
<ol>
<li>Create a patch by hacking on libprs500 and send it to me for review and inclusion. See
<a class="wiki" href="http://libprs500.kovidgoyal.net/wiki/Development">Development</a>.
<li>Create a patch by hacking on ${app} and send it to me for review and inclusion. See
<a class="wiki" href="http://${app}.kovidgoyal.net/wiki/Development">Development</a>.
</li>
<li><a href="http://libprs500.kovidgoyal.net/newticket">Open a ticket</a> (you have to register and login first) and hopefully I will find the time to implement your feature.
<li><a href="http://${app}.kovidgoyal.net/newticket">Open a ticket</a> (you have to register and login first) and hopefully I will find the time to implement your feature.
</li>
</ol>
@ -98,20 +100,9 @@
<p>
You can get help on any individual feature of the converters by mousing over it in the GUI or running html2lrf --help at a terminal. A good place to start is to look at the following demo files that demonstrate some of the advanced features:
</p>
<ul><li><a href="http://libprs500.kovidgoyal.net/downloads/html-demo.zip">html-demo.zip</a>
</li><li><a href="http://libprs500.kovidgoyal.net/downloads/txt-demo.zip">txt-demo.zip</a>
<ul><li><a href="http://${app}.kovidgoyal.net/downloads/html-demo.zip">html-demo.zip</a>
</li><li><a href="http://${app}.kovidgoyal.net/downloads/txt-demo.zip">txt-demo.zip</a>
</li></ul>
<hr />
<div class="footer">
<p>
<a href="http://validator.w3.org/check?uri=referer">
<img src="images/valid.png" alt="Valid XHTML 1.1" height="31" width="88" />
</a><br />
Created by Kovid Goyal &copy; 2008
</p>
</div>
</body>
</html>

View File

@ -1,23 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
<?python
title = 'Graphical User Interface'
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<meta name="author" content="Kovid Goyal" />
<meta name="copyright" content="2008 Kovid Goyal" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>The Graphical User Interface</title>
<link rel="stylesheet" type="text/css" href="styles/common.css" />
<title>${title}</title>
</head>
<body>
<h1 class="documentHeading">The Graphical User Interface</h1>
<p>
The Graphical User Interface <i>(GUI)</i> provides access to all
library management and ebook format conversion features. The basic workflow
for using libprs500 is to first add books to the library from your hard disk.
libprs500 will automatically try to read metadata from the books and add them
for using ${app} is to first add books to the library from your hard disk.
${app} will automatically try to read metadata from the books and add them
to its internal database. Once they are in the database, you can performa various
<a href="#actions">actions</a> on them that include conversion from one format to another,
transfer to the reading device, viewing on your computer, editing metadata, including covers, etc.
@ -193,8 +198,8 @@ Author
<p>
Ebooks can be converted from a number of formats into the LRF format (for the SONY Reader). Note that ebooks you purchase
will typically have <a href="http://en.wikipedia.org/wiki/Digital_rights_management">Digital Rights Management</a>
<i>(DRM)</i>. libprs500 will not convert these ebooks. For many DRM formats, it is easy to remove the DRM, but as this
is illegal, you have to find tools to liberate your books yourself and then use libprs500 to convert them.
<i>(DRM)</i>. ${app} will not convert these ebooks. For many DRM formats, it is easy to remove the DRM, but as this
is illegal, you have to find tools to liberate your books yourself and then use ${app} to convert them.
</p>
<p>
For most people, conversion should be a simple 1-click affair. But if you want to learn more about the
@ -223,7 +228,7 @@ Author
View
</h3>
<p>
The <span class="action">View</span> action displays the book in an ebook viewer program. libprs500 has a builtin
The <span class="action">View</span> action displays the book in an ebook viewer program. ${app} has a builtin
viewer for the LRF format. For other formats it uses the default operating system application. If a book has more than
one format, you can view a particular format by clicking the arrow next to the View button.
</p>
@ -232,14 +237,14 @@ Author
<h2 class="sectionHeading" id="catalogs">Catalogs</h2>
<div><img src="images/catalogs.png" alt="Catalogs"/></div>
<p>
A <i>catalog</i> is a collection of books. libprs500 can manage three different catalogs:
A <i>catalog</i> is a collection of books. ${app} can manage three different catalogs:
</p>
<ul>
<li>
<b>Library</b>: This is a collection of books stored in a database file on your computers hard disk.
<b>Reader</b>: This is a collection of books stored in the main memory of your ebook reader. It will be available
when you connect
<b>Card</b>: This is a collection of books stored on the storage card in your reader. Note that libprs500 supports
<b>Card</b>: This is a collection of books stored on the storage card in your reader. Note that ${app} supports
only a single storage card at a time.
</li>
</ul>
@ -305,7 +310,7 @@ Author
<hr />
<h2 class="sectionHeading" id="configuration">Configuration</h2>
<p>
The configuration dialog allows you to set some global defaults used by all of libprs500. To access it, click the
The configuration dialog allows you to set some global defaults used by all of ${app}. To access it, click the
<img src="images/configuration.png" alt="Configuration" /> button.
</p>
@ -326,16 +331,7 @@ Author
Once a job has completed, by clicking it in the list, you can see a detailed log from that job. This is useful
to debug jobs that may not have completed successfully.
</p>
<hr />
<div class="footer">
<p>
<a href="http://validator.w3.org/check?uri=referer">
<img src="images/valid.png" alt="Valid XHTML 1.1" height="31" width="88" />
</a><br />
Created by Kovid Goyal &copy; 2008
</p>
</div>
</body>

View File

@ -1,13 +1,13 @@
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta name="author" content="Kovid Goyal" />
<meta name="copyright" content="&copy; 2008 Kovid Goyal" />
<meta name="author" content="${author}" />
<meta name="copyright" content="&copy; 2008 ${author}" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>libprs500 User Manual</title>
<title>${app} User Manual</title>
</head>
<frameset cols="25%, 75%">

View File

@ -0,0 +1,38 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
py:strip=""
>
<py:match path="head">
<head py:attrs="select('@*')">
<meta name="author" content="${author}" />
<meta name="copyright" content="&copy; 2008 ${author}" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="stylesheet" type="text/css" href="styles/common.css" />
${select('*|text()')}
</head>
</py:match>
<py:match path="body">
<body py:attrs="select('@*')">
<h1 class="documentHeading">
${title}
</h1>
${select('*|text()')}
<py:if test="footer">
<hr />
<div class="footer">
<p>
<a href="http://validator.w3.org/check?uri=referer">
<img src="images/valid.png" alt="Valid XHTML 1.0" height="31" width="88" />
</a><br />
Created by ${author} &copy; 2008
</p>
</div>
</py:if>
</body>
</py:match>
</html>

View File

@ -1,12 +1,21 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<?python
title = '%s Manual'%app
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script>
<link rel="stylesheet" href="http://dev.jquery.com/view/trunk/plugins/treeview/jquery.treeview.css" type="text/css">
<link rel="stylesheet" href="styles/common.css" type="text/css">
<script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/treeview/jquery.treeview.js"></script>
<title>${title}</title>
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript" />
<link rel="stylesheet" href="http://dev.jquery.com/view/trunk/plugins/treeview/jquery.treeview.css" type="text/css" />
<script type="text/javascript" src="http://dev.jquery.com/view/trunk/plugins/treeview/jquery.treeview.js" />
<style type="text/css">
#browser {
font-family: monospace;
@ -25,23 +34,26 @@
$("#browser").treeview({collapsed:true});
});
</script>
<title>libprs500 User Manual</title>
</head>
<body>
<h2 class="documentHeading">libprs500 Manual</h2>
<ul id="browser" class="filetree">
%tree
<py:for each="section in toc">
<li py:with="cl='toplevel %s'%('folder' if section['subsections'] else 'file')"
class="${cl}">
<a target="content" href="${section['href']}">${section['title']}</a>
<py:if test="section['subsections']">
<ul>
<py:for each="ss in section['subsections']">
<li class="nottoplevel file">
<a target="content" href="${ss['href']}">${ss['title']}</a>
</li>
</py:for>
</ul>
</py:if>
</li>
</py:for>
</ul>
<hr>
<div class="footer">
<p>
<a href="http://validator.w3.org/check?uri=referer">
<img src="http://www.w3.org/Icons/valid-html401-blue" alt="Valid HTML 4.01 Transitional" height="31" width="88">
</a><br>
Created by Kovid Goyal &copy; 2008
</p>
</div>
</body>
</html>

View File

@ -0,0 +1,28 @@
<?python
title = 'Using custom news sources'
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<title>${title}</title>
</head>
<body>
<p>
${app} contains a very powerful and flexible engine to make fetching
news from the Internet and converting it to a nicely formatted ebook,
really easy. The easiest way to explain its full power and ease-of-use
is through examples, so lets get started...
</p>
</body>
</html>

View File

@ -1,21 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" >
<?python
title = '%s User Manual'%app
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xml:lang="en"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:py="http://genshi.edgewall.org/"
>
<xi:include href="layout.html" />
<head>
<meta name="author" content="Kovid Goyal" />
<meta name="copyright" content="&copy; 2008 Kovid Goyal" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>libprs500 User Manual</title>
<link rel="stylesheet" type="text/css" href="styles/common.css" />
<title>${title}</title>
</head>
<body>
<h1 class="documentHeading">libprs500 User Manual</h1>
<p>
<b>libprs500</b> is an e-book library manager. It can view, convert and catalog e-books
<b>${app}</b> is an e-book library manager. It can view, convert and catalog e-books
in most of the major e-book formats. It can also talk to a few e-book reader devices. It can
go out to the internet and fetch metadata for your books. It can download newspapers and convert
them into e-books for convenient reading. It is cross platform, running on Linux, Windows and OS X.
@ -23,7 +27,7 @@
<p>
To get started you should use the <a href="gui.html">Graphical User Interface</a>. It can be launched
using its icon or the command <span class="cmd">libprs500</span>.
using its icon or the command <span class="cmd">${app}</span>.
</p>
<p>
@ -38,18 +42,9 @@
<ul id="toc">
<li><a href="gui.html">Graphical User Interface</a></li>
<li><a href="cli-index.html">Command Line Interface</a></li>
<li><a href="news.html">Using custom news sources</a></li>
<li><a href="faq.html">Frequently Asked Questions</a></li>
</ul>
<hr />
<div class="footer">
<p>
<a href="http://validator.w3.org/check?uri=referer">
<img src="images/valid.png" alt="Valid XHTML 1.1" height="31" width="88" />
</a><br />
Created by Kovid Goyal &copy; 2008
</p>
</div>
</body>
</html>

View File

@ -57,7 +57,7 @@ def build_installer(installer, vm, timeout=25):
sys.stdout.flush()
print
if not os.path.exists(installer):
raise Exception('Failed to build windows installer')
raise Exception('Failed to build installer '+installer)
finally:
os.unlink('dist/auto')
@ -116,10 +116,7 @@ def upload_user_manual():
try:
check_call('python make.py --validate')
check_call('ssh castalia rm -rf %s/\\*'%USER_MANUAL)
check_call('ssh castalia mkdir %(um)s/styles %(um)s/images'%dict(um=USER_MANUAL))
check_call('scp *.html castalia:%s/'%USER_MANUAL)
check_call('scp styles/* castalia:%s/styles/'%USER_MANUAL)
check_call('scp images/* castalia:%s/images/'%USER_MANUAL)
check_call('scp -r build/* castalia:%s'%USER_MANUAL)
finally:
os.chdir(cwd)