Upgrade python error checker to use pyflakes 0.4 and fix te new errors found by it
@ -11,7 +11,7 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
class ChicagoBreakingNews(BasicNewsRecipe):
|
class ChicagoBreakingNews(BasicNewsRecipe):
|
||||||
title = 'Chicago Breaking News'
|
title = 'Chicago Breaking News'
|
||||||
__author__ = 'Darko Miletic'
|
__author__ = 'Darko Miletic'
|
||||||
description = 'Breaking News from Chicago'
|
description = 'Breaking News from Chicago'
|
||||||
oldest_article = 1
|
oldest_article = 1
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
@ -21,19 +21,18 @@ class ChicagoBreakingNews(BasicNewsRecipe):
|
|||||||
encoding = 'utf8'
|
encoding = 'utf8'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
|
|
||||||
|
|
||||||
html2lrf_options = [
|
html2lrf_options = [
|
||||||
'--comment', description
|
'--comment', description
|
||||||
, '--category', category
|
, '--category', category
|
||||||
, '--publisher', publisher
|
, '--publisher', publisher
|
||||||
]
|
]
|
||||||
|
|
||||||
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
html2epub_options = 'publisher="' + publisher + '"\ncomments="' + description + '"\ntags="' + category + '"'
|
||||||
|
|
||||||
feeds = [(u'Breaking news', u'http://feeds2.feedburner.com/ChicagoBreakingNews/')]
|
feeds = [(u'Breaking news', u'http://feeds2.feedburner.com/ChicagoBreakingNews/')]
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
links = soup.findAll('a')
|
|
||||||
for item in soup.findAll('a'):
|
for item in soup.findAll('a'):
|
||||||
if item['href'].find('http://feedads.googleadservices.com') > -1:
|
if item['href'].find('http://feedads.googleadservices.com') > -1:
|
||||||
item.extract()
|
item.extract()
|
||||||
|
@ -80,7 +80,6 @@ class GlasSrpske(BasicNewsRecipe):
|
|||||||
for item in soup.findAll('div', attrs={'class':'gl_rub'}):
|
for item in soup.findAll('div', attrs={'class':'gl_rub'}):
|
||||||
atag = item.find('a')
|
atag = item.find('a')
|
||||||
ptag = item.find('p')
|
ptag = item.find('p')
|
||||||
datetag = item.find('span')
|
|
||||||
url = self.INDEX + atag['href']
|
url = self.INDEX + atag['href']
|
||||||
title = self.tag_to_string(atag)
|
title = self.tag_to_string(atag)
|
||||||
description = self.tag_to_string(ptag)
|
description = self.tag_to_string(ptag)
|
||||||
|
@ -147,7 +147,6 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
# Fetch the outer table
|
# Fetch the outer table
|
||||||
table = soup.find('table')
|
table = soup.find('table')
|
||||||
previousTable = table
|
previousTable = table
|
||||||
contentTable = None
|
|
||||||
|
|
||||||
# Find the deepest table containing the stories
|
# Find the deepest table containing the stories
|
||||||
while True :
|
while True :
|
||||||
|
@ -53,8 +53,8 @@ class NYTimes(BasicNewsRecipe):
|
|||||||
articles = {}
|
articles = {}
|
||||||
key = None
|
key = None
|
||||||
ans = []
|
ans = []
|
||||||
allSectionKeywords = ['The Front Page', 'International','National','Obituaries','Editorials',
|
#allSectionKeywords = ['The Front Page', 'International','National','Obituaries','Editorials',
|
||||||
'New York','Business Day','Sports','Dining','Arts','Home','Styles']
|
#'New York','Business Day','Sports','Dining','Arts','Home','Styles']
|
||||||
excludeSectionKeywords = ['Dining','Styles']
|
excludeSectionKeywords = ['Dining','Styles']
|
||||||
|
|
||||||
|
|
||||||
|
@ -71,7 +71,6 @@ class ScientificAmerican(BasicNewsRecipe):
|
|||||||
feeds.append(('Features', features))
|
feeds.append(('Features', features))
|
||||||
|
|
||||||
section = []
|
section = []
|
||||||
found = []
|
|
||||||
title = None
|
title = None
|
||||||
|
|
||||||
for x in soup.find(id='magazine-main_col1').findAll(['div', 'a']):
|
for x in soup.find(id='magazine-main_col1').findAll(['div', 'a']):
|
||||||
|
@ -72,7 +72,6 @@ class Time(BasicNewsRecipe):
|
|||||||
return feeds
|
return feeds
|
||||||
|
|
||||||
def find_articles(self, seched):
|
def find_articles(self, seched):
|
||||||
articles = []
|
|
||||||
for a in seched.findNextSiblings( attrs={'class':['toc_hed','rule2']}):
|
for a in seched.findNextSiblings( attrs={'class':['toc_hed','rule2']}):
|
||||||
if a.name in "div":
|
if a.name in "div":
|
||||||
break
|
break
|
||||||
|
@ -1,76 +1,76 @@
|
|||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
from calibre.ebooks.BeautifulSoup import Tag
|
from calibre.ebooks.BeautifulSoup import Tag
|
||||||
|
|
||||||
class VrijNederlandRecipe(BasicNewsRecipe) :
|
class VrijNederlandRecipe(BasicNewsRecipe) :
|
||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__author__ = 'kwetal'
|
__author__ = 'kwetal'
|
||||||
language = 'nl_NL'
|
language = 'nl_NL'
|
||||||
locale = 'nl_NL'
|
locale = 'nl_NL'
|
||||||
version = 1
|
version = 1
|
||||||
|
|
||||||
title = u'Vrij Nederland'
|
title = u'Vrij Nederland'
|
||||||
publisher = u'Weekbladpers Tijdschriften'
|
publisher = u'Weekbladpers Tijdschriften'
|
||||||
category = u'News, Opinion'
|
category = u'News, Opinion'
|
||||||
description = u'Weekly opinion magazine from the Netherlands'
|
description = u'Weekly opinion magazine from the Netherlands'
|
||||||
|
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
use_embedded_content = False
|
use_embedded_content = False
|
||||||
|
|
||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
# Does not seem to work
|
# Does not seem to work
|
||||||
#extra_css = '''li.calibre2 {padding-bottom: 40px}'''
|
#extra_css = '''li.calibre2 {padding-bottom: 40px}'''
|
||||||
|
|
||||||
conversion_options = {'publisher': publisher, 'tags': category, 'comments': description}
|
conversion_options = {'publisher': publisher, 'tags': category, 'comments': description}
|
||||||
|
|
||||||
feeds = []
|
feeds = []
|
||||||
feeds.append((u'Politiek', u'http://www.vn.nl/politiek.rss'))
|
feeds.append((u'Politiek', u'http://www.vn.nl/politiek.rss'))
|
||||||
feeds.append((u'Buitenland', u'http://www.vn.nl/buitenland.rss'))
|
feeds.append((u'Buitenland', u'http://www.vn.nl/buitenland.rss'))
|
||||||
feeds.append((u'Economie', u'http://www.vn.nl/economie.rss'))
|
feeds.append((u'Economie', u'http://www.vn.nl/economie.rss'))
|
||||||
feeds.append((u'Justitie', u'http://www.vn.nl/justitie.rss'))
|
feeds.append((u'Justitie', u'http://www.vn.nl/justitie.rss'))
|
||||||
feeds.append((u'Samenleving', u'http://www.vn.nl/samenleving.rss'))
|
feeds.append((u'Samenleving', u'http://www.vn.nl/samenleving.rss'))
|
||||||
feeds.append((u'Crime', u'http://www.vn.nl/crime.rss'))
|
feeds.append((u'Crime', u'http://www.vn.nl/crime.rss'))
|
||||||
feeds.append((u'Media', u'http://www.vn.nl/media.rss'))
|
feeds.append((u'Media', u'http://www.vn.nl/media.rss'))
|
||||||
feeds.append((u'De Republiek der Letteren', u'http://www.vn.nl/republiek.rss'))
|
feeds.append((u'De Republiek der Letteren', u'http://www.vn.nl/republiek.rss'))
|
||||||
feeds.append((u'Max van Weezel', u'http://www.vn.nl/vanweezel.rss'))
|
feeds.append((u'Max van Weezel', u'http://www.vn.nl/vanweezel.rss'))
|
||||||
feeds.append((u'Ko Colijn', u'http://www.vn.nl/colijn.rss'))
|
feeds.append((u'Ko Colijn', u'http://www.vn.nl/colijn.rss'))
|
||||||
feeds.append((u'Kees Kraaijeveld', u'http://www.vn.nl/kraaijeveld.rss'))
|
feeds.append((u'Kees Kraaijeveld', u'http://www.vn.nl/kraaijeveld.rss'))
|
||||||
feeds.append((u'Frank Kalshoven', u'http://www.vn.nl/kalshoven.rss'))
|
feeds.append((u'Frank Kalshoven', u'http://www.vn.nl/kalshoven.rss'))
|
||||||
feeds.append((u'Stephan Sanders', u'http://www.vn.nl/sanders.rss'))
|
feeds.append((u'Stephan Sanders', u'http://www.vn.nl/sanders.rss'))
|
||||||
feeds.append((u'Micha Wertheim', u'http://www.vn.nl/wertheim.rss'))
|
feeds.append((u'Micha Wertheim', u'http://www.vn.nl/wertheim.rss'))
|
||||||
feeds.append((u'Arnon Grunberg', u'http://www.vn.nl/grunberg.rss'))
|
feeds.append((u'Arnon Grunberg', u'http://www.vn.nl/grunberg.rss'))
|
||||||
feeds.append((u'Carel Peeters', u'http://www.vn.nl/carelpeeters.rss'))
|
feeds.append((u'Carel Peeters', u'http://www.vn.nl/carelpeeters.rss'))
|
||||||
|
|
||||||
keep_only_tags = [dict(name = 'div', attrs = {'class' : 'cl-column column-one'})]
|
keep_only_tags = [dict(name = 'div', attrs = {'class' : 'cl-column column-one'})]
|
||||||
|
|
||||||
remove_tags = []
|
remove_tags = []
|
||||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'wpg-element guest-book-overview'}))
|
remove_tags.append(dict(name = 'div', attrs = {'class' : 'wpg-element guest-book-overview'}))
|
||||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'wpg-element forum-message-form'}))
|
remove_tags.append(dict(name = 'div', attrs = {'class' : 'wpg-element forum-message-form'}))
|
||||||
remove_tags.append(dict(name = 'div', attrs = {'class' : 'mediaterms'}))
|
remove_tags.append(dict(name = 'div', attrs = {'class' : 'mediaterms'}))
|
||||||
remove_tags.append(dict(name = 'div', attrs = {'class': 'label-term'}))
|
remove_tags.append(dict(name = 'div', attrs = {'class': 'label-term'}))
|
||||||
remove_tags.append(dict(name = 'div', attrs = {'class': 'wpg-element Media-Collection-Element-Artikel-Lijst'}))
|
remove_tags.append(dict(name = 'div', attrs = {'class': 'wpg-element Media-Collection-Element-Artikel-Lijst'}))
|
||||||
remove_tags.append(dict(name = 'object'))
|
remove_tags.append(dict(name = 'object'))
|
||||||
remove_tags.append(dict(name = 'link'))
|
remove_tags.append(dict(name = 'link'))
|
||||||
remove_tags.append(dict(name = 'meta'))
|
remove_tags.append(dict(name = 'meta'))
|
||||||
|
|
||||||
def preprocess_html(self, soup):
|
def preprocess_html(self, soup):
|
||||||
# Just clean up the result a little
|
# Just clean up the result a little
|
||||||
meta = soup.find('div', attrs = {'class': 'meta'})
|
meta = soup.find('div', attrs = {'class': 'meta'})
|
||||||
if meta:
|
if meta:
|
||||||
link = meta.find('span', attrs = {'class': 'link'})
|
link = meta.find('span', attrs = {'class': 'link'})
|
||||||
if link:
|
if link:
|
||||||
link.extract()
|
link.extract()
|
||||||
for seperator in meta.findAll('span', attrs = {'class': 'seperator'}):
|
for seperator in meta.findAll('span', attrs = {'class': 'seperator'}):
|
||||||
seperator.extract()
|
seperator.extract()
|
||||||
|
|
||||||
# Their header is full of 'if IE6/7/8' tags. Just get rid of it altogether
|
# Their header is full of 'if IE6/7/8' tags. Just get rid of it altogether
|
||||||
theirHead = soup.head
|
theirHead = soup.head
|
||||||
theirHead.extract()
|
theirHead.extract()
|
||||||
myHead = Tag(soup, 'head')
|
myHead = Tag(soup, 'head')
|
||||||
soup.insert(0, myHead)
|
soup.insert(0, myHead)
|
||||||
|
|
||||||
return soup
|
return soup
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -7,33 +7,57 @@ __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
|
|||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import sys, os, cPickle, subprocess
|
import sys, os, cPickle, subprocess
|
||||||
from operator import attrgetter
|
|
||||||
from setup import Command
|
from setup import Command
|
||||||
|
import __builtin__
|
||||||
|
|
||||||
def check_for_python_errors(filename, builtins):
|
def set_builtins(builtins):
|
||||||
from pyflakes import checker, ast
|
for x in builtins:
|
||||||
|
if not hasattr(__builtin__, x):
|
||||||
|
setattr(__builtin__, x, True)
|
||||||
|
yield x
|
||||||
|
|
||||||
contents = open(filename, 'rb').read()
|
class Message:
|
||||||
|
|
||||||
|
def __init__(self, filename, lineno, msg):
|
||||||
|
self.filename, self.lineno, self.msg = filename, lineno, msg
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return '%s:%s: %s'%(self.filename, self.lineno, self.msg)
|
||||||
|
|
||||||
|
def check_for_python_errors(code_string, filename):
|
||||||
|
# Since compiler.parse does not reliably report syntax errors, use the
|
||||||
|
# built in compiler first to detect those.
|
||||||
try:
|
try:
|
||||||
tree = ast.parse(contents, filename)
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
|
||||||
try:
|
try:
|
||||||
value = sys.exc_info()[1]
|
compile(code_string, filename, "exec")
|
||||||
lineno, offset, line = value[1][1:]
|
except MemoryError:
|
||||||
except IndexError:
|
# Python 2.4 will raise MemoryError if the source can't be
|
||||||
lineno, offset, line = 1, 0, ''
|
# decoded.
|
||||||
if line.endswith("\n"):
|
if sys.version_info[:2] == (2, 4):
|
||||||
line = line[:-1]
|
raise SyntaxError(None)
|
||||||
|
raise
|
||||||
|
except (SyntaxError, IndentationError), value:
|
||||||
|
msg = value.args[0]
|
||||||
|
|
||||||
return [SyntaxError(filename, lineno, offset, str(value))]
|
(lineno, offset, text) = value.lineno, value.offset, value.text
|
||||||
|
|
||||||
|
# If there's an encoding problem with the file, the text is None.
|
||||||
|
if text is None:
|
||||||
|
# Avoid using msg, since for the only known case, it contains a
|
||||||
|
# bogus message that claims the encoding the file declared was
|
||||||
|
# unknown.
|
||||||
|
msg = "%s: problem decoding source" % filename
|
||||||
|
return [Message(filename, lineno, msg)]
|
||||||
else:
|
else:
|
||||||
w = checker.Checker(tree, filename, builtins = builtins)
|
# Okay, it's syntactically valid. Now parse it into an ast and check
|
||||||
w.messages.sort(key = attrgetter('lineno'))
|
# it.
|
||||||
return w.messages
|
import compiler
|
||||||
|
checker = __import__('pyflakes.checker').checker
|
||||||
|
tree = compiler.parse(code_string)
|
||||||
|
w = checker.Checker(tree, filename)
|
||||||
|
w.messages.sort(lambda a, b: cmp(a.lineno, b.lineno))
|
||||||
|
return [Message(x.filename, x.lineno, x.message%x.message_args) for x in
|
||||||
|
w.messages]
|
||||||
|
|
||||||
class Check(Command):
|
class Check(Command):
|
||||||
|
|
||||||
@ -65,15 +89,18 @@ class Check(Command):
|
|||||||
cache = {}
|
cache = {}
|
||||||
if os.path.exists(self.CACHE):
|
if os.path.exists(self.CACHE):
|
||||||
cache = cPickle.load(open(self.CACHE, 'rb'))
|
cache = cPickle.load(open(self.CACHE, 'rb'))
|
||||||
|
builtins = list(set_builtins(self.BUILTINS))
|
||||||
for f, mtime in self.get_files(cache):
|
for f, mtime in self.get_files(cache):
|
||||||
self.info('\tChecking', f)
|
self.info('\tChecking', f)
|
||||||
w = check_for_python_errors(f, self.BUILTINS)
|
w = check_for_python_errors(open(f, 'rb').read(), f)
|
||||||
if w:
|
if w:
|
||||||
self.report_errors(w)
|
self.report_errors(w)
|
||||||
cPickle.dump(cache, open(self.CACHE, 'wb'), -1)
|
cPickle.dump(cache, open(self.CACHE, 'wb'), -1)
|
||||||
subprocess.call(['gvim', '-f', f])
|
subprocess.call(['gvim', '-f', f])
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
cache[f] = mtime
|
cache[f] = mtime
|
||||||
|
for x in builtins:
|
||||||
|
delattr(__builtin__, x)
|
||||||
cPickle.dump(cache, open(self.CACHE, 'wb'), -1)
|
cPickle.dump(cache, open(self.CACHE, 'wb'), -1)
|
||||||
wn_path = os.path.expanduser('~/work/servers/src/calibre_servers/main')
|
wn_path = os.path.expanduser('~/work/servers/src/calibre_servers/main')
|
||||||
if os.path.exists(wn_path):
|
if os.path.exists(wn_path):
|
||||||
@ -85,11 +112,5 @@ class Check(Command):
|
|||||||
|
|
||||||
def report_errors(self, errors):
|
def report_errors(self, errors):
|
||||||
for err in errors:
|
for err in errors:
|
||||||
if isinstance(err, SyntaxError):
|
self.info('\t\t', str(err))
|
||||||
print '\t\tSyntax Error'
|
|
||||||
else:
|
|
||||||
col = getattr(err, 'col', 0) if getattr(err, 'col', 0) else 0
|
|
||||||
lineno = err.lineno if err.lineno else 0
|
|
||||||
self.info('\t\t%d:%d:'%(lineno, col),
|
|
||||||
err.message%err.message_args)
|
|
||||||
|
|
||||||
|
@ -606,7 +606,6 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
def eject_linux(self):
|
def eject_linux(self):
|
||||||
drives = self.find_device_nodes()
|
drives = self.find_device_nodes()
|
||||||
success = False
|
|
||||||
for drive in drives:
|
for drive in drives:
|
||||||
if drive:
|
if drive:
|
||||||
cmd = 'calibre-mount-helper'
|
cmd = 'calibre-mount-helper'
|
||||||
|
@ -43,7 +43,6 @@ class FB2Input(InputFormatPlugin):
|
|||||||
from calibre.ebooks.oeb.base import XLINK_NS
|
from calibre.ebooks.oeb.base import XLINK_NS
|
||||||
NAMESPACES = {'f':FB2NS, 'l':XLINK_NS}
|
NAMESPACES = {'f':FB2NS, 'l':XLINK_NS}
|
||||||
log.debug('Parsing XML...')
|
log.debug('Parsing XML...')
|
||||||
parser = etree.XMLParser(recover=True, no_network=True)
|
|
||||||
doc = etree.fromstring(stream.read())
|
doc = etree.fromstring(stream.read())
|
||||||
self.extract_embedded_content(doc)
|
self.extract_embedded_content(doc)
|
||||||
log.debug('Converting XML to HTML...')
|
log.debug('Converting XML to HTML...')
|
||||||
|
@ -106,7 +106,7 @@ def process_file(lrfpath, opts, logger=None):
|
|||||||
os.makedirs(opts.out)
|
os.makedirs(opts.out)
|
||||||
|
|
||||||
document = LRFDocument(open(lrfpath, 'rb'))
|
document = LRFDocument(open(lrfpath, 'rb'))
|
||||||
conv = LRFConverter(document, opts, logger)
|
LRFConverter(document, opts, logger)
|
||||||
|
|
||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
|
@ -2207,7 +2207,7 @@ class JumpButton(LrsObject, LrsContainer):
|
|||||||
def toElement(self, se):
|
def toElement(self, se):
|
||||||
b = self.lrsObjectElement("Button")
|
b = self.lrsObjectElement("Button")
|
||||||
pb = SubElement(b, "PushButton")
|
pb = SubElement(b, "PushButton")
|
||||||
jt = SubElement(pb, "JumpTo",
|
SubElement(pb, "JumpTo",
|
||||||
refpage=str(self.textBlock.parent.objId),
|
refpage=str(self.textBlock.parent.objId),
|
||||||
refobj=str(self.textBlock.objId))
|
refobj=str(self.textBlock.objId))
|
||||||
return b
|
return b
|
||||||
|
@ -323,7 +323,7 @@ class MobiReader(object):
|
|||||||
self.log.warning('Malformed markup, parsing using BeautifulSoup')
|
self.log.warning('Malformed markup, parsing using BeautifulSoup')
|
||||||
try:
|
try:
|
||||||
root = soupparser.fromstring(self.processed_html)
|
root = soupparser.fromstring(self.processed_html)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
self.log.warning('MOBI markup appears to contain random bytes. Stripping.')
|
self.log.warning('MOBI markup appears to contain random bytes. Stripping.')
|
||||||
self.processed_html = self.remove_random_bytes(self.processed_html)
|
self.processed_html = self.remove_random_bytes(self.processed_html)
|
||||||
root = soupparser.fromstring(self.processed_html)
|
root = soupparser.fromstring(self.processed_html)
|
||||||
|
@ -510,7 +510,7 @@ class MobiWriter(object):
|
|||||||
self._oeb.log.warning('_generate_flat_indexed_navpoints: Failed to generate index')
|
self._oeb.log.warning('_generate_flat_indexed_navpoints: Failed to generate index')
|
||||||
# Zero out self._HTMLRecords, return False
|
# Zero out self._HTMLRecords, return False
|
||||||
self._HTMLRecords = []
|
self._HTMLRecords = []
|
||||||
last_name = None
|
#last_name = None
|
||||||
return False
|
return False
|
||||||
|
|
||||||
previousOffset = offset
|
previousOffset = offset
|
||||||
@ -545,7 +545,7 @@ class MobiWriter(object):
|
|||||||
if self.opts.verbose > 3 : self._oeb.logger.info(" node %03d: %-15.15s... spans HTML records %03d - %03d \t offset: 0x%06X length: 0x%06X" % \
|
if self.opts.verbose > 3 : self._oeb.logger.info(" node %03d: %-15.15s... spans HTML records %03d - %03d \t offset: 0x%06X length: 0x%06X" % \
|
||||||
(myIndex, child.title if child.title.strip() > "" else "(missing)", myStartingRecord, myStartingRecord, offset, length) )
|
(myIndex, child.title if child.title.strip() > "" else "(missing)", myStartingRecord, myStartingRecord, offset, length) )
|
||||||
|
|
||||||
last_name = "%04X" % myIndex
|
#last_name = "%04X" % myIndex
|
||||||
myIndex += 1
|
myIndex += 1
|
||||||
|
|
||||||
# Successfully parsed the entries
|
# Successfully parsed the entries
|
||||||
@ -625,7 +625,7 @@ class MobiWriter(object):
|
|||||||
self._oeb.log.warning('_generate_indexed_navpoints: Failed to generate index')
|
self._oeb.log.warning('_generate_indexed_navpoints: Failed to generate index')
|
||||||
# Zero out self._HTMLRecords, return False
|
# Zero out self._HTMLRecords, return False
|
||||||
self._HTMLRecords = []
|
self._HTMLRecords = []
|
||||||
last_name = None
|
#last_name = None
|
||||||
return False
|
return False
|
||||||
|
|
||||||
previousOffset = offset
|
previousOffset = offset
|
||||||
@ -659,7 +659,7 @@ class MobiWriter(object):
|
|||||||
# *** This should check currentSectionNumber, because content could start late
|
# *** This should check currentSectionNumber, because content could start late
|
||||||
if thisRecord > 0:
|
if thisRecord > 0:
|
||||||
sectionChangesInThisRecord = True
|
sectionChangesInThisRecord = True
|
||||||
sectionChangesInRecordNumber = thisRecord
|
#sectionChangesInRecordNumber = thisRecord
|
||||||
self._currentSectionIndex += 1
|
self._currentSectionIndex += 1
|
||||||
self._HTMLRecords[thisRecord].nextSectionNumber = self._currentSectionIndex
|
self._HTMLRecords[thisRecord].nextSectionNumber = self._currentSectionIndex
|
||||||
# The following node opens the nextSection
|
# The following node opens the nextSection
|
||||||
@ -717,7 +717,7 @@ class MobiWriter(object):
|
|||||||
if self.opts.verbose > 3 : self._oeb.logger.info(" node: %03d %-10.10s %-15.15s... spans HTML records %03d-%03d \t offset: 0x%06X length: 0x%06X" % \
|
if self.opts.verbose > 3 : self._oeb.logger.info(" node: %03d %-10.10s %-15.15s... spans HTML records %03d-%03d \t offset: 0x%06X length: 0x%06X" % \
|
||||||
(myIndex, self._ctoc_map[i]['klass'], child.title if child.title.strip() > "" else "(missing)", thisRecord, thisRecord, offset, length) )
|
(myIndex, self._ctoc_map[i]['klass'], child.title if child.title.strip() > "" else "(missing)", thisRecord, thisRecord, offset, length) )
|
||||||
|
|
||||||
last_name = "%04X" % myIndex
|
#last_name = "%04X" % myIndex
|
||||||
myIndex += 1
|
myIndex += 1
|
||||||
|
|
||||||
# Successfully parsed the entries
|
# Successfully parsed the entries
|
||||||
@ -1999,7 +1999,7 @@ class MobiWriter(object):
|
|||||||
self._articleCount = 0
|
self._articleCount = 0
|
||||||
self._chapterCount = 0
|
self._chapterCount = 0
|
||||||
|
|
||||||
first = True
|
#first = True
|
||||||
|
|
||||||
if self._conforming_periodical_toc :
|
if self._conforming_periodical_toc :
|
||||||
self._oeb.logger.info('Generating structured CTOC ...')
|
self._oeb.logger.info('Generating structured CTOC ...')
|
||||||
@ -2007,7 +2007,7 @@ class MobiWriter(object):
|
|||||||
if self.opts.verbose > 2 :
|
if self.opts.verbose > 2 :
|
||||||
self._oeb.logger.info(" %s" % child)
|
self._oeb.logger.info(" %s" % child)
|
||||||
self._add_structured_ctoc_node(child, self._ctoc)
|
self._add_structured_ctoc_node(child, self._ctoc)
|
||||||
first = False
|
#first = False
|
||||||
|
|
||||||
else :
|
else :
|
||||||
self._oeb.logger.info('Generating flat CTOC ...')
|
self._oeb.logger.info('Generating flat CTOC ...')
|
||||||
@ -2025,7 +2025,6 @@ class MobiWriter(object):
|
|||||||
# Test to see if this child's offset is the same as the previous child's
|
# Test to see if this child's offset is the same as the previous child's
|
||||||
# offset, skip it
|
# offset, skip it
|
||||||
h = child.href
|
h = child.href
|
||||||
first = False
|
|
||||||
|
|
||||||
if h is None:
|
if h is None:
|
||||||
self._oeb.logger.warn(' Ignoring TOC entry with no href:',
|
self._oeb.logger.warn(' Ignoring TOC entry with no href:',
|
||||||
@ -2345,7 +2344,7 @@ class MobiWriter(object):
|
|||||||
self._oeb.logger.info( "Writing NCXEntries for mobiType 0x%03X" % myDoc.mobiType)
|
self._oeb.logger.info( "Writing NCXEntries for mobiType 0x%03X" % myDoc.mobiType)
|
||||||
|
|
||||||
sectionParent = myDoc.documentStructure.sectionParents[0]
|
sectionParent = myDoc.documentStructure.sectionParents[0]
|
||||||
articleCount = len(sectionParent.articles)
|
#articleCount = len(sectionParent.articles)
|
||||||
|
|
||||||
# Write opening periodical 0xDF entry
|
# Write opening periodical 0xDF entry
|
||||||
index = 0
|
index = 0
|
||||||
@ -2361,7 +2360,7 @@ class MobiWriter(object):
|
|||||||
while sectionCount <= lastSection :
|
while sectionCount <= lastSection :
|
||||||
# section
|
# section
|
||||||
sectionParent = myDoc.documentStructure.sectionParents[sectionCount - 1]
|
sectionParent = myDoc.documentStructure.sectionParents[sectionCount - 1]
|
||||||
articleCount = len(sectionParent.articles)
|
#articleCount = len(sectionParent.articles)
|
||||||
#index += 1
|
#index += 1
|
||||||
offset = sectionParent.startAddress
|
offset = sectionParent.startAddress
|
||||||
length = sectionParent.sectionLength
|
length = sectionParent.sectionLength
|
||||||
|
@ -168,7 +168,6 @@ class OEBReader(object):
|
|||||||
manifest = self.oeb.manifest
|
manifest = self.oeb.manifest
|
||||||
known = set(manifest.hrefs)
|
known = set(manifest.hrefs)
|
||||||
unchecked = set(manifest.values())
|
unchecked = set(manifest.values())
|
||||||
bad = []
|
|
||||||
while unchecked:
|
while unchecked:
|
||||||
new = set()
|
new = set()
|
||||||
for item in unchecked:
|
for item in unchecked:
|
||||||
|
@ -103,7 +103,7 @@ def run(opts, pathtopdf, log):
|
|||||||
pdfreflow.reflow(data)
|
pdfreflow.reflow(data)
|
||||||
index = os.path.join(os.getcwdu(), 'index.xml')
|
index = os.path.join(os.getcwdu(), 'index.xml')
|
||||||
xml = open(index, 'rb').read()
|
xml = open(index, 'rb').read()
|
||||||
#pdfdoc = PDFDocument(xml, opts, log)
|
PDFDocument(xml, opts, log)
|
||||||
|
|
||||||
def option_parser():
|
def option_parser():
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
@ -20,7 +20,7 @@ def is_valid_pdf(pdf_path):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
with open(os.path.abspath(pdf_path), 'rb') as pdf_file:
|
with open(os.path.abspath(pdf_path), 'rb') as pdf_file:
|
||||||
pdf = PdfFileReader(pdf_file)
|
PdfFileReader(pdf_file)
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
@ -610,7 +610,6 @@ class DeviceGUI(object):
|
|||||||
def emails_sent(self, results, remove=[]):
|
def emails_sent(self, results, remove=[]):
|
||||||
errors, good = [], []
|
errors, good = [], []
|
||||||
for jobname, exception, tb in results:
|
for jobname, exception, tb in results:
|
||||||
id = jobname.partition(':')[0]
|
|
||||||
title = jobname.partition(':')[-1]
|
title = jobname.partition(':')[-1]
|
||||||
if exception is not None:
|
if exception is not None:
|
||||||
errors.append([title, exception, tb])
|
errors.append([title, exception, tb])
|
||||||
|
@ -135,7 +135,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata):
|
|||||||
set_isbndb_key(key)
|
set_isbndb_key(key)
|
||||||
else:
|
else:
|
||||||
key = None
|
key = None
|
||||||
title = author = publisher = isbn = pubdate = None
|
title = author = publisher = isbn = None
|
||||||
if self.isbn:
|
if self.isbn:
|
||||||
isbn = self.isbn
|
isbn = self.isbn
|
||||||
if self.title:
|
if self.title:
|
||||||
|
@ -50,7 +50,7 @@ class TagEditor(QDialog, Ui_TagEditor):
|
|||||||
confirms, deletes = [], []
|
confirms, deletes = [], []
|
||||||
items = self.available_tags.selectedItems() if item is None else [item]
|
items = self.available_tags.selectedItems() if item is None else [item]
|
||||||
if not items:
|
if not items:
|
||||||
d = error_dialog(self, 'No tags selected', 'You must select at least one tag from the list of Available tags.').exec_()
|
error_dialog(self, 'No tags selected', 'You must select at least one tag from the list of Available tags.').exec_()
|
||||||
return
|
return
|
||||||
for item in items:
|
for item in items:
|
||||||
if self.db.is_tag_used(qstring_to_unicode(item.text())):
|
if self.db.is_tag_used(qstring_to_unicode(item.text())):
|
||||||
|
@ -125,7 +125,6 @@ class JobManager(QAbstractTableModel):
|
|||||||
|
|
||||||
def _update(self):
|
def _update(self):
|
||||||
# Update running time
|
# Update running time
|
||||||
rows = set([])
|
|
||||||
for i, j in enumerate(self.jobs):
|
for i, j in enumerate(self.jobs):
|
||||||
if j.run_state == j.RUNNING:
|
if j.run_state == j.RUNNING:
|
||||||
idx = self.index(i, 3)
|
idx = self.index(i, 3)
|
||||||
|
@ -186,7 +186,7 @@ class TextBlock(object):
|
|||||||
try:
|
try:
|
||||||
self.populate(tb.content)
|
self.populate(tb.content)
|
||||||
self.end_line()
|
self.end_line()
|
||||||
except TextBlock.HeightExceeded, err:
|
except TextBlock.HeightExceeded:
|
||||||
pass
|
pass
|
||||||
#logger.warning('TextBlock height exceeded, skipping line:\n%s'%(err,))
|
#logger.warning('TextBlock height exceeded, skipping line:\n%s'%(err,))
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
self.stack.setCurrentIndex(0)
|
self.stack.setCurrentIndex(0)
|
||||||
try:
|
try:
|
||||||
db = LibraryDatabase2(self.library_path)
|
db = LibraryDatabase2(self.library_path)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
import traceback
|
import traceback
|
||||||
error_dialog(self, _('Bad database location'),
|
error_dialog(self, _('Bad database location'),
|
||||||
_('Bad database location')+':'+self.library_path,
|
_('Bad database location')+':'+self.library_path,
|
||||||
@ -1033,7 +1033,6 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
def download_metadata(self, checked, covers=True, set_metadata=True,
|
def download_metadata(self, checked, covers=True, set_metadata=True,
|
||||||
set_social_metadata=None):
|
set_social_metadata=None):
|
||||||
rows = self.library_view.selectionModel().selectedRows()
|
rows = self.library_view.selectionModel().selectedRows()
|
||||||
previous = self.library_view.currentIndex()
|
|
||||||
if not rows or len(rows) == 0:
|
if not rows or len(rows) == 0:
|
||||||
d = error_dialog(self, _('Cannot download metadata'),
|
d = error_dialog(self, _('Cannot download metadata'),
|
||||||
_('No books selected'))
|
_('No books selected'))
|
||||||
@ -1071,7 +1070,7 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
|||||||
x = self._download_book_metadata
|
x = self._download_book_metadata
|
||||||
self._download_book_metadata = None
|
self._download_book_metadata = None
|
||||||
if x.exception is None:
|
if x.exception is None:
|
||||||
db = self.library_view.model().refresh_ids(
|
self.library_view.model().refresh_ids(
|
||||||
x.updated, cr)
|
x.updated, cr)
|
||||||
if x.failures:
|
if x.failures:
|
||||||
details = ['%s: %s'%(title, reason) for title,
|
details = ['%s: %s'%(title, reason) for title,
|
||||||
|
@ -141,6 +141,7 @@ class TagsModel(QAbstractItemModel):
|
|||||||
data=self.categories[i], category_icon=self.cmap[i])
|
data=self.categories[i], category_icon=self.cmap[i])
|
||||||
for tag in data[r]:
|
for tag in data[r]:
|
||||||
t = TagTreeItem(parent=c, data=tag, icon_map=self.icon_map)
|
t = TagTreeItem(parent=c, data=tag, icon_map=self.icon_map)
|
||||||
|
t
|
||||||
|
|
||||||
self.db.add_listener(self.database_changed)
|
self.db.add_listener(self.database_changed)
|
||||||
self.connect(self, SIGNAL('need_refresh()'), self.refresh,
|
self.connect(self, SIGNAL('need_refresh()'), self.refresh,
|
||||||
@ -229,7 +230,6 @@ class TagsModel(QAbstractItemModel):
|
|||||||
def reset_all_states(self):
|
def reset_all_states(self):
|
||||||
for i in xrange(self.rowCount(QModelIndex())):
|
for i in xrange(self.rowCount(QModelIndex())):
|
||||||
category_index = self.index(i, 0, QModelIndex())
|
category_index = self.index(i, 0, QModelIndex())
|
||||||
category_item = category_index.internalPointer()
|
|
||||||
for j in xrange(self.rowCount(category_index)):
|
for j in xrange(self.rowCount(category_index)):
|
||||||
tag_index = self.index(j, 0, category_index)
|
tag_index = self.index(j, 0, category_index)
|
||||||
tag_item = tag_index.internalPointer()
|
tag_item = tag_index.internalPointer()
|
||||||
|
@ -95,10 +95,6 @@ def convert_single_ebook(parent, db, book_ids, auto_conversion=False, out_format
|
|||||||
return jobs, changed, bad
|
return jobs, changed, bad
|
||||||
|
|
||||||
def convert_bulk_ebook(parent, queue, db, book_ids, out_format=None, args=[]):
|
def convert_bulk_ebook(parent, queue, db, book_ids, out_format=None, args=[]):
|
||||||
changed = False
|
|
||||||
jobs = []
|
|
||||||
bad = []
|
|
||||||
|
|
||||||
total = len(book_ids)
|
total = len(book_ids)
|
||||||
if total == 0:
|
if total == 0:
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
@ -437,7 +437,7 @@ def move_library(oldloc, newloc, parent, callback_on_complete):
|
|||||||
|
|
||||||
# Try to load existing library at new location
|
# Try to load existing library at new location
|
||||||
try:
|
try:
|
||||||
ndb = LibraryDatabase2(newloc)
|
LibraryDatabase2(newloc)
|
||||||
except Exception, err:
|
except Exception, err:
|
||||||
det = traceback.format_exc()
|
det = traceback.format_exc()
|
||||||
error_dialog(parent, _('Invalid database'),
|
error_dialog(parent, _('Invalid database'),
|
||||||
|
@ -889,10 +889,8 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
def formats(self, index, index_is_id=False):
|
def formats(self, index, index_is_id=False):
|
||||||
''' Return available formats as a comma separated list or None if there are no available formats '''
|
''' Return available formats as a comma separated list or None if there are no available formats '''
|
||||||
id = index if index_is_id else self.id(index)
|
id = index if index_is_id else self.id(index)
|
||||||
path = os.path.join(self.library_path, self.path(id, index_is_id=True))
|
|
||||||
try:
|
try:
|
||||||
formats = self.conn.get('SELECT format FROM data WHERE book=?', (id,))
|
formats = self.conn.get('SELECT format FROM data WHERE book=?', (id,))
|
||||||
name = self.conn.get('SELECT name FROM data WHERE book=?', (id,), all=False)
|
|
||||||
formats = map(lambda x:x[0], formats)
|
formats = map(lambda x:x[0], formats)
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
@ -910,7 +908,10 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
def format_abspath(self, index, format, index_is_id=False):
|
def format_abspath(self, index, format, index_is_id=False):
|
||||||
'Return absolute path to the ebook file of format `format`'
|
'Return absolute path to the ebook file of format `format`'
|
||||||
id = index if index_is_id else self.id(index)
|
id = index if index_is_id else self.id(index)
|
||||||
name = self.conn.get('SELECT name FROM data WHERE book=? AND format=?', (id, format), all=False)
|
try:
|
||||||
|
name = self.conn.get('SELECT name FROM data WHERE book=? AND format=?', (id, format), all=False)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
if name:
|
if name:
|
||||||
path = os.path.join(self.library_path, self.path(id, index_is_id=True))
|
path = os.path.join(self.library_path, self.path(id, index_is_id=True))
|
||||||
format = ('.' + format.lower()) if format else ''
|
format = ('.' + format.lower()) if format else ''
|
||||||
@ -1813,11 +1814,9 @@ books_series_link feeds
|
|||||||
else:
|
else:
|
||||||
actual_formats = [x.lower() for x in actual_formats.split(',')]
|
actual_formats = [x.lower() for x in actual_formats.split(',')]
|
||||||
|
|
||||||
mismatch = False
|
|
||||||
for fmt in formats:
|
for fmt in formats:
|
||||||
if fmt in actual_formats:
|
if fmt in actual_formats:
|
||||||
continue
|
continue
|
||||||
mismatch = True
|
|
||||||
if id not in bad:
|
if id not in bad:
|
||||||
bad[id] = []
|
bad[id] = []
|
||||||
bad[id].append(fmt)
|
bad[id].append(fmt)
|
||||||
|
@ -636,10 +636,6 @@ class LibraryServer(object):
|
|||||||
'type="application/atom+xml" href="/stanza/?%s"/>\n'
|
'type="application/atom+xml" href="/stanza/?%s"/>\n'
|
||||||
) % '&'.join(q)
|
) % '&'.join(q)
|
||||||
|
|
||||||
author_list=[]
|
|
||||||
tag_list=[]
|
|
||||||
series_list=[]
|
|
||||||
|
|
||||||
for record in nrecord_list:
|
for record in nrecord_list:
|
||||||
r = record[FIELD_MAP['formats']]
|
r = record[FIELD_MAP['formats']]
|
||||||
r = r.upper() if r else ''
|
r = r.upper() if r else ''
|
||||||
|
@ -388,7 +388,7 @@ class PostInstall:
|
|||||||
finally:
|
finally:
|
||||||
os.chdir(cwd)
|
os.chdir(cwd)
|
||||||
shutil.rmtree(tdir)
|
shutil.rmtree(tdir)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
if self.opts.fatal_errors:
|
if self.opts.fatal_errors:
|
||||||
raise
|
raise
|
||||||
self.task_failed('Setting up desktop integration failed')
|
self.task_failed('Setting up desktop integration failed')
|
||||||
|
@ -127,7 +127,6 @@ def generate_ebook_convert_help(preamble, info):
|
|||||||
input and the output formats, the various combinations are listed below:
|
input and the output formats, the various combinations are listed below:
|
||||||
|
|
||||||
''')
|
''')
|
||||||
sections = []
|
|
||||||
toc = {}
|
toc = {}
|
||||||
sec_templ = textwrap.dedent('''\
|
sec_templ = textwrap.dedent('''\
|
||||||
.. include:: ../global.rst
|
.. include:: ../global.rst
|
||||||
@ -141,7 +140,6 @@ def generate_ebook_convert_help(preamble, info):
|
|||||||
|
|
||||||
''')
|
''')
|
||||||
for i, ip in enumerate(input_format_plugins()):
|
for i, ip in enumerate(input_format_plugins()):
|
||||||
path = os.path.join('cli', 'ebook-convert-%d.rst'%i)
|
|
||||||
sraw = sec_templ.format(ip.name)
|
sraw = sec_templ.format(ip.name)
|
||||||
toc[ip.name] = 'ebook-convert-%d'%i
|
toc[ip.name] = 'ebook-convert-%d'%i
|
||||||
for op in output_format_plugins():
|
for op in output_format_plugins():
|
||||||
|
@ -262,7 +262,7 @@ class QtHelpBuilder(StandaloneHTMLBuilder):
|
|||||||
shortname = shortname[:-2]
|
shortname = shortname[:-2]
|
||||||
id = '%s.%s' % (id, shortname)
|
id = '%s.%s' % (id, shortname)
|
||||||
else:
|
else:
|
||||||
id = descr = None
|
id = None
|
||||||
|
|
||||||
if id:
|
if id:
|
||||||
item = ' '*12 + '<keyword name="%s" id="%s" ref="%s"/>' % (
|
item = ' '*12 + '<keyword name="%s" id="%s" ref="%s"/>' % (
|
||||||
|
@ -1,80 +0,0 @@
|
|||||||
'''
|
|
||||||
Trac Macro to generate an end use Changelog from the svn logs.
|
|
||||||
'''
|
|
||||||
import re, collections, time, os
|
|
||||||
|
|
||||||
from bzrlib import log as blog, branch
|
|
||||||
|
|
||||||
from cStringIO import StringIO
|
|
||||||
|
|
||||||
from trac.wiki.formatter import Formatter
|
|
||||||
from trac.wiki.macros import WikiMacroBase
|
|
||||||
from trac.util import Markup
|
|
||||||
|
|
||||||
|
|
||||||
BZR_PATH = '/usr/local/calibre'
|
|
||||||
|
|
||||||
class ChangelogFormatter(blog.LogFormatter):
|
|
||||||
|
|
||||||
supports_tags = True
|
|
||||||
supports_merge_revisions = False
|
|
||||||
_show_advice = False
|
|
||||||
|
|
||||||
def __init__(self, num_of_versions=20):
|
|
||||||
self.num_of_versions = num_of_versions
|
|
||||||
self.messages = collections.deque()
|
|
||||||
self.entries = []
|
|
||||||
self.current_entry = None
|
|
||||||
|
|
||||||
def log_revision(self, r):
|
|
||||||
if len(self.entries) > self.num_of_versions-1:
|
|
||||||
return
|
|
||||||
msg = r.rev.message
|
|
||||||
match = re.match(r'version\s+(\d+\.\d+.\d+)', msg)
|
|
||||||
|
|
||||||
if match:
|
|
||||||
if self.current_entry is not None:
|
|
||||||
self.entries.append((self.current_entry, set(self.messages)))
|
|
||||||
timestamp = r.rev.timezone + r.rev.timestamp
|
|
||||||
self.current_entry = match.group(1) + time.strftime(' (%d %b, %Y)', time.gmtime(timestamp))
|
|
||||||
self.messages = collections.deque()
|
|
||||||
|
|
||||||
else:
|
|
||||||
if re.search(r'[a-zA-Z]', msg) and len(msg.strip()) > 5:
|
|
||||||
if 'translation' not in msg and not msg.startswith('IGN'):
|
|
||||||
self.messages.append(msg.strip())
|
|
||||||
|
|
||||||
def to_wiki_txt(self):
|
|
||||||
txt = ['= Changelog =\n[[PageOutline]]']
|
|
||||||
for entry in self.entries:
|
|
||||||
txt.append(u'----\n== Version '+entry[0]+' ==')
|
|
||||||
if entry[0].strip().startswith('0.6.0'):
|
|
||||||
txt.append(u'For a list of new features in 0.6.0 see http://calibre.kovidgoyal.net/new_in_6')
|
|
||||||
else:
|
|
||||||
for msg in entry[1]:
|
|
||||||
txt.append(u' * ' + msg)
|
|
||||||
|
|
||||||
return (u'\n'.join(txt)).encode('ascii', 'replace')
|
|
||||||
|
|
||||||
def bzr_log_to_txt():
|
|
||||||
path = BZR_PATH
|
|
||||||
if not os.path.exists(path):
|
|
||||||
path = '/home/kovid/work/calibre'
|
|
||||||
b = branch.Branch.open(path)
|
|
||||||
lf = ChangelogFormatter()
|
|
||||||
blog.show_log(b, lf)
|
|
||||||
return lf.to_wiki_txt()
|
|
||||||
|
|
||||||
class ChangeLogMacro(WikiMacroBase):
|
|
||||||
|
|
||||||
def expand_macro(self, formatter, name, args):
|
|
||||||
txt = bzr_log_to_txt().encode('ascii', 'xmlcharrefreplace')
|
|
||||||
out = StringIO()
|
|
||||||
Formatter(formatter.env, formatter.context).format(txt, out)
|
|
||||||
return Markup(out.getvalue().decode('utf8'))
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
print bzr_log_to_txt().encode('utf-8')
|
|
||||||
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
||||||
|
|
@ -1,405 +0,0 @@
|
|||||||
__license__ = 'GPL v3'
|
|
||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|
||||||
__appname__ = 'calibre'
|
|
||||||
import re, textwrap
|
|
||||||
|
|
||||||
DEPENDENCIES = [
|
|
||||||
#(Generic, version, gentoo, ubuntu, fedora)
|
|
||||||
('python', '2.6', None, None, None),
|
|
||||||
('Python Imaging Library', '1.1.6', 'imaging', 'python-imaging', 'python-imaging'),
|
|
||||||
('libusb', '0.1.12', None, None, None),
|
|
||||||
('Qt', '4.5.1', 'qt', 'libqt4-core libqt4-gui', 'qt4'),
|
|
||||||
('PyQt', '4.6.1', 'PyQt4', 'python-qt4', 'PyQt4'),
|
|
||||||
('python-mechanize', '0.1.11', 'dev-python/mechanize', 'python-mechanize', 'python-mechanize'),
|
|
||||||
('ImageMagick', '6.3.5', 'imagemagick', 'imagemagick', 'ImageMagick'),
|
|
||||||
('xdg-utils', '1.0.2', 'xdg-utils', 'xdg-utils', 'xdg-utils'),
|
|
||||||
('lxml', '2.1.5', 'lxml', 'python-lxml', 'python-lxml'),
|
|
||||||
('python-dateutil', '1.4.1', 'python-dateutil', 'python-dateutil', 'python-dateutil'),
|
|
||||||
('BeautifulSoup', '3.0.5', 'beautifulsoup', 'python-beautifulsoup', 'python-BeautifulSoup'),
|
|
||||||
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
|
|
||||||
('poppler', '0.12.0', 'poppler', 'poppler', 'poppler', 'poppler'),
|
|
||||||
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
|
|
||||||
('libwmf', '0.2.8', 'libwmf', 'libwmf', 'libwmf', 'libwmf'),
|
|
||||||
]
|
|
||||||
STATUS = 'http://status.calibre-ebook.com/dist'
|
|
||||||
|
|
||||||
class CoolDistro:
|
|
||||||
|
|
||||||
def __init__(self, name, title, prefix=''):
|
|
||||||
self.title = title
|
|
||||||
url = prefix + '/chrome/dl/images/%s_logo.png'
|
|
||||||
self.img = url%name
|
|
||||||
|
|
||||||
def get_linux_data(version='1.0.0'):
|
|
||||||
data = {'version':version, 'app':__appname__}
|
|
||||||
data['title'] = 'Download calibre for linux'
|
|
||||||
data['supported'] = []
|
|
||||||
for name, title in [
|
|
||||||
('debian', 'Debian Sid'),
|
|
||||||
('exherbo', 'Exherbo'),
|
|
||||||
('foresight', 'Foresight 2.1'),
|
|
||||||
('gentoo', 'Gentoo'),
|
|
||||||
('ubuntu', 'Ubuntu Jaunty Jackalope'),
|
|
||||||
('linux_mint', 'Linux Mint Gloria'),
|
|
||||||
]:
|
|
||||||
data['supported'].append(CoolDistro(name, title,
|
|
||||||
prefix='http://calibre.kovidgoyal.net'))
|
|
||||||
data['dependencies'] = DEPENDENCIES
|
|
||||||
return data
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import os
|
|
||||||
from calibre.utils.genshi.template import MarkupTemplate
|
|
||||||
import cherrypy
|
|
||||||
class Test:
|
|
||||||
def index(self):
|
|
||||||
raw = open(os.path.dirname(os.path.abspath(__file__))+'/templates/linux.html').read()
|
|
||||||
return MarkupTemplate(raw).generate(**get_linux_data()).render('xhtml')
|
|
||||||
index.exposed = True
|
|
||||||
t = Test()
|
|
||||||
t.index()
|
|
||||||
cherrypy.quickstart(t)
|
|
||||||
else:
|
|
||||||
from pkg_resources import resource_filename
|
|
||||||
|
|
||||||
from trac.core import Component, implements
|
|
||||||
from trac.web.chrome import INavigationContributor, ITemplateProvider, add_stylesheet
|
|
||||||
from trac.web.main import IRequestHandler
|
|
||||||
from trac.util import Markup
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DOWNLOAD_DIR = '/var/www/calibre.kovidgoyal.net/htdocs/downloads'
|
|
||||||
MOBILEREAD = 'https://dev.mobileread.com/dist/kovid/calibre/'
|
|
||||||
#MOBILEREAD = 'http://calibre.kovidgoyal.net/downloads/'
|
|
||||||
|
|
||||||
class OS(dict):
|
|
||||||
"""Dictionary with a default value for unknown keys."""
|
|
||||||
def __init__(self, dict):
|
|
||||||
self.update(dict)
|
|
||||||
if not dict.has_key('img'):
|
|
||||||
self['img'] = self['name']
|
|
||||||
|
|
||||||
|
|
||||||
class Download(Component):
|
|
||||||
implements(INavigationContributor, IRequestHandler, ITemplateProvider)
|
|
||||||
|
|
||||||
request_pat = re.compile(r'\/download$|\/download_\S+')
|
|
||||||
|
|
||||||
# INavigationContributor methods
|
|
||||||
def get_active_navigation_item(self, req):
|
|
||||||
return 'download'
|
|
||||||
|
|
||||||
def get_navigation_items(self, req):
|
|
||||||
yield 'mainnav', 'download', Markup('<a href="/download">Get %s</a>'%(__appname__,))
|
|
||||||
|
|
||||||
def get_templates_dirs(self):
|
|
||||||
return [resource_filename(__name__, 'templates')]
|
|
||||||
|
|
||||||
def get_htdocs_dirs(self):
|
|
||||||
return [('dl', resource_filename(__name__, 'htdocs'))]
|
|
||||||
|
|
||||||
# IRequestHandler methods
|
|
||||||
def match_request(self, req):
|
|
||||||
return self.__class__.request_pat.match(req.path_info)
|
|
||||||
|
|
||||||
def process_request(self, req):
|
|
||||||
add_stylesheet(req, 'dl/css/download.css')
|
|
||||||
if req.path_info == '/download':
|
|
||||||
return self.top_level(req)
|
|
||||||
elif req.path_info == '/download_linux_binary_installer':
|
|
||||||
req.send(LINUX_INSTALLER.replace('%version', self.version_from_filename()), 'text/x-python')
|
|
||||||
else:
|
|
||||||
match = re.match(r'\/download_(\S+)', req.path_info)
|
|
||||||
if match:
|
|
||||||
os = match.group(1)
|
|
||||||
if os == 'windows':
|
|
||||||
return self.windows(req)
|
|
||||||
elif os == 'osx':
|
|
||||||
return self.osx(req)
|
|
||||||
elif os == 'linux':
|
|
||||||
return self.linux(req)
|
|
||||||
|
|
||||||
def top_level(self, req):
|
|
||||||
operating_systems = [
|
|
||||||
OS({'name' : 'windows', 'title' : 'Windows'}),
|
|
||||||
OS({'name' : 'osx', 'title' : 'OS X'}),
|
|
||||||
OS({'name' : 'linux', 'title' : 'Linux'}),
|
|
||||||
]
|
|
||||||
data = dict(title='Get ' + __appname__,
|
|
||||||
operating_systems=operating_systems, width=200,
|
|
||||||
font_size='xx-large', top_level=True)
|
|
||||||
return 'download.html', data, None
|
|
||||||
|
|
||||||
def version_from_filename(self):
|
|
||||||
try:
|
|
||||||
return open(DOWNLOAD_DIR+'/latest_version', 'rb').read().strip()
|
|
||||||
except:
|
|
||||||
return '0.0.0'
|
|
||||||
|
|
||||||
def windows(self, req):
|
|
||||||
version = self.version_from_filename()
|
|
||||||
file = '%s-%s.msi'%(__appname__, version,)
|
|
||||||
data = dict(version = version, name='windows',
|
|
||||||
installer_name='Windows installer',
|
|
||||||
title='Download %s for windows'%(__appname__),
|
|
||||||
compatibility=('%(a)s works on Windows XP, Vista and 7.'
|
|
||||||
'If you are upgrading from a version older than 0.6.17, '
|
|
||||||
'please uninstall %(a)s first.')%dict(a=__appname__,),
|
|
||||||
path=STATUS+'/win32', app=__appname__,
|
|
||||||
note=Markup(\
|
|
||||||
'''
|
|
||||||
<p>If you are updating from a version of calibre older than 0.6.12 on
|
|
||||||
<b>Windows XP</b>, first uninstall calibre, then delete the C:\Program
|
|
||||||
Files\calibre folder (the location may be different if you previously
|
|
||||||
installed calibre elsewhere) and only then install the new version of
|
|
||||||
calibre.</p><p><br /></p>
|
|
||||||
<p>If you are using the <b>SONY PRS-500</b> and %(appname)s does not detect your reader, read on:</p>
|
|
||||||
<blockquote>
|
|
||||||
<p>
|
|
||||||
If you are using 64-bit windows, you're out of luck.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
There may be a conflict with the USB driver from SONY. In windows, you cannot install two drivers
|
|
||||||
for one device. In order to resolve the conflict:
|
|
||||||
<ol>
|
|
||||||
<li>Start Device Manager by clicking Start->Run, typing devmgmt.msc and pressing enter.</li>
|
|
||||||
<li>Uninstall all PRS500 related drivers. You will find them in two locations:
|
|
||||||
<ul>
|
|
||||||
<li>Under "Libusb-Win32"</li>
|
|
||||||
<li>Under "Universal Serial ..." (... depends on the version of windows)</li>
|
|
||||||
</ul>
|
|
||||||
You can uninstall a driver by right clicking on it and selecting uninstall.
|
|
||||||
</li>
|
|
||||||
<li>Once the drivers have been uninstalled, find the file prs500.inf (it will be in the
|
|
||||||
driver folder in the folder in which you installed %(appname)s. Right click on it and
|
|
||||||
select Install.</li>
|
|
||||||
</ol>
|
|
||||||
</p>
|
|
||||||
</blockquote>
|
|
||||||
'''%dict(appname=__appname__)))
|
|
||||||
return 'binary.html', data, None
|
|
||||||
|
|
||||||
def osx(self, req):
|
|
||||||
version = self.version_from_filename()
|
|
||||||
file = 'calibre-%s.dmg'%(version,)
|
|
||||||
data = dict(version = version, name='osx',
|
|
||||||
installer_name='OS X universal dmg',
|
|
||||||
title='Download %s for OS X'%(__appname__),
|
|
||||||
compatibility='%s works on OS X Tiger, Leopard, and Snow Leopard.'%(__appname__,),
|
|
||||||
path=STATUS+'/osx32', app=__appname__,
|
|
||||||
note=Markup(\
|
|
||||||
u'''
|
|
||||||
<ol>
|
|
||||||
<li>To install the command line tools, go to Preferences->Advanced</li>
|
|
||||||
<li>The app cannot be run from within the dmg. You must drag it to a folder on your filesystem (The Desktop, Applications, wherever).</li>
|
|
||||||
<li>In order for localization of the user interface in your language, select your language in the preferences (by pressing u\2318+P) and select your language.</li>
|
|
||||||
</ol>
|
|
||||||
'''))
|
|
||||||
return 'binary.html', data, None
|
|
||||||
|
|
||||||
def linux(self, req):
|
|
||||||
data = get_linux_data(version=self.version_from_filename())
|
|
||||||
return 'linux.html', data, None
|
|
||||||
|
|
||||||
|
|
||||||
LINUX_INSTALLER = textwrap.dedent(r'''
|
|
||||||
import sys, os, shutil, tarfile, subprocess, tempfile, urllib2, re, stat
|
|
||||||
|
|
||||||
MOBILEREAD='https://dev.mobileread.com/dist/kovid/calibre/'
|
|
||||||
#MOBILEREAD='http://calibre.kovidgoyal.net/downloads/'
|
|
||||||
|
|
||||||
|
|
||||||
class TerminalController:
|
|
||||||
BOL = '' #: Move the cursor to the beginning of the line
|
|
||||||
UP = '' #: Move the cursor up one line
|
|
||||||
DOWN = '' #: Move the cursor down one line
|
|
||||||
LEFT = '' #: Move the cursor left one char
|
|
||||||
RIGHT = '' #: Move the cursor right one char
|
|
||||||
|
|
||||||
# Deletion:
|
|
||||||
CLEAR_SCREEN = '' #: Clear the screen and move to home position
|
|
||||||
CLEAR_EOL = '' #: Clear to the end of the line.
|
|
||||||
CLEAR_BOL = '' #: Clear to the beginning of the line.
|
|
||||||
CLEAR_EOS = '' #: Clear to the end of the screen
|
|
||||||
|
|
||||||
# Output modes:
|
|
||||||
BOLD = '' #: Turn on bold mode
|
|
||||||
BLINK = '' #: Turn on blink mode
|
|
||||||
DIM = '' #: Turn on half-bright mode
|
|
||||||
REVERSE = '' #: Turn on reverse-video mode
|
|
||||||
NORMAL = '' #: Turn off all modes
|
|
||||||
|
|
||||||
# Cursor display:
|
|
||||||
HIDE_CURSOR = '' #: Make the cursor invisible
|
|
||||||
SHOW_CURSOR = '' #: Make the cursor visible
|
|
||||||
|
|
||||||
# Terminal size:
|
|
||||||
COLS = None #: Width of the terminal (None for unknown)
|
|
||||||
LINES = None #: Height of the terminal (None for unknown)
|
|
||||||
|
|
||||||
# Foreground colors:
|
|
||||||
BLACK = BLUE = GREEN = CYAN = RED = MAGENTA = YELLOW = WHITE = ''
|
|
||||||
|
|
||||||
# Background colors:
|
|
||||||
BG_BLACK = BG_BLUE = BG_GREEN = BG_CYAN = ''
|
|
||||||
BG_RED = BG_MAGENTA = BG_YELLOW = BG_WHITE = ''
|
|
||||||
|
|
||||||
_STRING_CAPABILITIES = """
|
|
||||||
BOL=cr UP=cuu1 DOWN=cud1 LEFT=cub1 RIGHT=cuf1
|
|
||||||
CLEAR_SCREEN=clear CLEAR_EOL=el CLEAR_BOL=el1 CLEAR_EOS=ed BOLD=bold
|
|
||||||
BLINK=blink DIM=dim REVERSE=rev UNDERLINE=smul NORMAL=sgr0
|
|
||||||
HIDE_CURSOR=cinvis SHOW_CURSOR=cnorm""".split()
|
|
||||||
_COLORS = """BLACK BLUE GREEN CYAN RED MAGENTA YELLOW WHITE""".split()
|
|
||||||
_ANSICOLORS = "BLACK RED GREEN YELLOW BLUE MAGENTA CYAN WHITE".split()
|
|
||||||
|
|
||||||
def __init__(self, term_stream=sys.stdout):
|
|
||||||
# Curses isn't available on all platforms
|
|
||||||
try: import curses
|
|
||||||
except: return
|
|
||||||
|
|
||||||
# If the stream isn't a tty, then assume it has no capabilities.
|
|
||||||
if not hasattr(term_stream, 'isatty') or not term_stream.isatty(): return
|
|
||||||
|
|
||||||
# Check the terminal type. If we fail, then assume that the
|
|
||||||
# terminal has no capabilities.
|
|
||||||
try: curses.setupterm()
|
|
||||||
except: return
|
|
||||||
|
|
||||||
# Look up numeric capabilities.
|
|
||||||
self.COLS = curses.tigetnum('cols')
|
|
||||||
self.LINES = curses.tigetnum('lines')
|
|
||||||
|
|
||||||
# Look up string capabilities.
|
|
||||||
for capability in self._STRING_CAPABILITIES:
|
|
||||||
(attrib, cap_name) = capability.split('=')
|
|
||||||
setattr(self, attrib, self._tigetstr(cap_name) or '')
|
|
||||||
|
|
||||||
# Colors
|
|
||||||
set_fg = self._tigetstr('setf')
|
|
||||||
if set_fg:
|
|
||||||
for i,color in zip(range(len(self._COLORS)), self._COLORS):
|
|
||||||
setattr(self, color, curses.tparm(set_fg, i) or '')
|
|
||||||
set_fg_ansi = self._tigetstr('setaf')
|
|
||||||
if set_fg_ansi:
|
|
||||||
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
|
|
||||||
setattr(self, color, curses.tparm(set_fg_ansi, i) or '')
|
|
||||||
set_bg = self._tigetstr('setb')
|
|
||||||
if set_bg:
|
|
||||||
for i,color in zip(range(len(self._COLORS)), self._COLORS):
|
|
||||||
setattr(self, 'BG_'+color, curses.tparm(set_bg, i) or '')
|
|
||||||
set_bg_ansi = self._tigetstr('setab')
|
|
||||||
if set_bg_ansi:
|
|
||||||
for i,color in zip(range(len(self._ANSICOLORS)), self._ANSICOLORS):
|
|
||||||
setattr(self, 'BG_'+color, curses.tparm(set_bg_ansi, i) or '')
|
|
||||||
|
|
||||||
def _tigetstr(self, cap_name):
|
|
||||||
# String capabilities can include "delays" of the form "$<2>".
|
|
||||||
# For any modern terminal, we should be able to just ignore
|
|
||||||
# these, so strip them out.
|
|
||||||
import curses
|
|
||||||
cap = curses.tigetstr(cap_name) or ''
|
|
||||||
return re.sub(r'\$<\d+>[/*]?', '', cap)
|
|
||||||
|
|
||||||
def render(self, template):
|
|
||||||
return re.sub(r'\$\$|\${\w+}', self._render_sub, template)
|
|
||||||
|
|
||||||
def _render_sub(self, match):
|
|
||||||
s = match.group()
|
|
||||||
if s == '$$': return s
|
|
||||||
else: return getattr(self, s[2:-1])
|
|
||||||
|
|
||||||
class ProgressBar:
|
|
||||||
BAR = '%3d%% ${GREEN}[${BOLD}%s%s${NORMAL}${GREEN}]${NORMAL}\n'
|
|
||||||
HEADER = '${BOLD}${CYAN}%s${NORMAL}\n\n'
|
|
||||||
|
|
||||||
def __init__(self, term, header):
|
|
||||||
self.term = term
|
|
||||||
if not (self.term.CLEAR_EOL and self.term.UP and self.term.BOL):
|
|
||||||
raise ValueError("Terminal isn't capable enough -- you "
|
|
||||||
"should use a simpler progress dispaly.")
|
|
||||||
self.width = self.term.COLS or 75
|
|
||||||
self.bar = term.render(self.BAR)
|
|
||||||
self.header = self.term.render(self.HEADER % header.center(self.width))
|
|
||||||
self.cleared = 1 #: true if we haven't drawn the bar yet.
|
|
||||||
|
|
||||||
def update(self, percent, message=''):
|
|
||||||
if isinstance(message, unicode):
|
|
||||||
message = message.encode('utf-8', 'ignore')
|
|
||||||
if self.cleared:
|
|
||||||
sys.stdout.write(self.header)
|
|
||||||
self.cleared = 0
|
|
||||||
n = int((self.width-10)*percent)
|
|
||||||
msg = message.center(self.width)
|
|
||||||
sys.stdout.write(
|
|
||||||
self.term.BOL + self.term.UP + self.term.CLEAR_EOL +
|
|
||||||
(self.bar % (100*percent, '='*n, '-'*(self.width-10-n))) +
|
|
||||||
self.term.CLEAR_EOL + msg)
|
|
||||||
sys.stdout.flush()
|
|
||||||
|
|
||||||
def clear(self):
|
|
||||||
if not self.cleared:
|
|
||||||
sys.stdout.write(self.term.BOL + self.term.CLEAR_EOL +
|
|
||||||
self.term.UP + self.term.CLEAR_EOL +
|
|
||||||
self.term.UP + self.term.CLEAR_EOL)
|
|
||||||
self.cleared = 1
|
|
||||||
|
|
||||||
def download_tarball():
|
|
||||||
try:
|
|
||||||
pb = ProgressBar(TerminalController(sys.stdout), 'Downloading calibre...')
|
|
||||||
except ValueError:
|
|
||||||
print 'Downloading calibre...'
|
|
||||||
pb = None
|
|
||||||
local = 'calibre-test.tar.bz2'
|
|
||||||
src = open(local) if os.access(local, os.R_OK) else urllib2.urlopen(MOBILEREAD+'calibre-%version-i686.tar.bz2')
|
|
||||||
if hasattr(src, 'info'):
|
|
||||||
size = int(src.info()['content-length'])
|
|
||||||
else:
|
|
||||||
src.seek(0, 2)
|
|
||||||
size = src.tell()
|
|
||||||
src.seek(0)
|
|
||||||
f = tempfile.NamedTemporaryFile()
|
|
||||||
while f.tell() < size:
|
|
||||||
f.write(src.read(4*1024))
|
|
||||||
percent = f.tell()/float(size)
|
|
||||||
if pb is not None:
|
|
||||||
pb.update(percent)
|
|
||||||
else:
|
|
||||||
print '%d%%, '%int(percent*100),
|
|
||||||
f.seek(0)
|
|
||||||
return f
|
|
||||||
|
|
||||||
def extract_tarball(tar, destdir):
|
|
||||||
print 'Extracting application files...'
|
|
||||||
if hasattr(tar, 'read'):
|
|
||||||
subprocess.check_call(['tar', 'xjf', tar.name, '-C', destdir])
|
|
||||||
else:
|
|
||||||
subprocess.check_call(['tar', 'xjf', tar, '-C', destdir])
|
|
||||||
|
|
||||||
def main():
|
|
||||||
defdir = '/opt/calibre'
|
|
||||||
destdir = raw_input('Enter the installation directory for calibre (Its contents will be deleted!)[%s]: '%defdir).strip()
|
|
||||||
if not destdir:
|
|
||||||
destdir = defdir
|
|
||||||
destdir = os.path.abspath(destdir)
|
|
||||||
if os.path.exists(destdir):
|
|
||||||
shutil.rmtree(destdir)
|
|
||||||
os.makedirs(destdir)
|
|
||||||
|
|
||||||
f = download_tarball()
|
|
||||||
|
|
||||||
print 'Extracting files to %s ...'%destdir
|
|
||||||
extract_tarball(f, destdir)
|
|
||||||
mh = os.path.join(destdir, 'calibre-mount-helper')
|
|
||||||
if os.geteuid() == 0:
|
|
||||||
os.chown(mh, 0, 0)
|
|
||||||
os.chmod(mh,
|
|
||||||
stat.S_ISUID|stat.S_ISGID|stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
|
|
||||||
else:
|
|
||||||
print 'WARNING: Not running as root. Cannot install mount helper.',
|
|
||||||
print 'Device automounting may not work.'
|
|
||||||
|
|
||||||
pi = os.path.join(destdir, 'calibre_postinstall')
|
|
||||||
subprocess.call(pi, shell=True)
|
|
||||||
return 0
|
|
||||||
''')
|
|
Before Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 42 KiB |
Before Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 95 KiB |
@ -1,40 +0,0 @@
|
|||||||
<!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"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="layout.html" />
|
|
||||||
<head>
|
|
||||||
<title>$title</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="ctxtnav" class="nav"></div>
|
|
||||||
|
|
||||||
<div id="content" class="binary">
|
|
||||||
<h1>$title</h1>
|
|
||||||
<p>$compatibility</p>
|
|
||||||
<p>
|
|
||||||
<a style="border: 0px" href="$path">
|
|
||||||
<img width="50" height="50" style="border:1px red solid" src="${href.chrome('/dl/images/%s_logo.png'%(name,))}" /> $installer_name
|
|
||||||
</a> (Version: $version <a href="/wiki/Changelog">Changelog</a>)
|
|
||||||
</p>
|
|
||||||
While you wait for the download to complete, please consider donating to support the development
|
|
||||||
of ${app}. If the above link does not work, the files are also available from
|
|
||||||
<a href="https://sourceforge.net/projects/calibre/">sourceforge</a>.
|
|
||||||
<div>
|
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
|
||||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
|
||||||
<input type="hidden" name="hosted_button_id" value="3029289" />
|
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="Donate to support calibre development" />
|
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
|
||||||
</form>
|
|
||||||
<br />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<h2>Note</h2>
|
|
||||||
<div class="note">$note</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,41 +0,0 @@
|
|||||||
<!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"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="layout.html" />
|
|
||||||
<head>
|
|
||||||
<title>$title</title>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="ctxtnav" class="nav"></div>
|
|
||||||
<p py:if="not top_level">If you have a 64bit computer, or an outdated operating system, the distribution
|
|
||||||
specific installation may not work for you. In that case, first try the binary installer.
|
|
||||||
If that also does not work, your only recourse is to try to install from source. In order
|
|
||||||
to do that you will have to install all the dependencies as well as the -dev package of PyQt4.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div id="content" class="download">
|
|
||||||
<h1>$title</h1>
|
|
||||||
<center>
|
|
||||||
<table cellspacing="40px">
|
|
||||||
<tr>
|
|
||||||
<td style="text-align:center; font-size: ${font_size}" py:for="os in operating_systems">
|
|
||||||
<a href="download_${os['name']}" style="text-decoration:none; border:0;">
|
|
||||||
<img width="${width}" height="${width+20}" src="${href.chrome('/dl/images/%s_logo.png'%(os['img'],))}" />
|
|
||||||
</a>
|
|
||||||
<a href="download_${os['name']}" style="text-decoration:none; border:0">
|
|
||||||
<br />
|
|
||||||
${os['title']}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<br />
|
|
||||||
|
|
||||||
</center>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1,165 +0,0 @@
|
|||||||
<!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"
|
|
||||||
xmlns:py="http://genshi.edgewall.org/"
|
|
||||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
|
||||||
<xi:include href="layout.html" />
|
|
||||||
<head>
|
|
||||||
<title>${title}</title>
|
|
||||||
<style type="text/css">
|
|
||||||
table tr th.distro_type {
|
|
||||||
font-family: monospace;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: larger;
|
|
||||||
vertical-align:middle;
|
|
||||||
text-align: center;
|
|
||||||
border-bottom: solid 1pt black;
|
|
||||||
}
|
|
||||||
|
|
||||||
.right {
|
|
||||||
margin-left:2em;
|
|
||||||
border-left: solid 1pt black;
|
|
||||||
}
|
|
||||||
|
|
||||||
table#install_info {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-width: 1pt;
|
|
||||||
border-style: solid;
|
|
||||||
table-layout: fixed;
|
|
||||||
width: 95%;
|
|
||||||
background: #F7F7F0 none repeat scroll 0 0;
|
|
||||||
}
|
|
||||||
table#dependencies {
|
|
||||||
border-collapse: collapse;
|
|
||||||
border-width: 0pt;
|
|
||||||
font-family:monospace;
|
|
||||||
}
|
|
||||||
.tdata {vertical-align: top;}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<div id="ctxtnav" class="nav"></div>
|
|
||||||
<div id="content" class="download">
|
|
||||||
<h1>${title}</h1>
|
|
||||||
<p>
|
|
||||||
The latest release of ${app} is ${version}. See the
|
|
||||||
<a href="/wiki/Changelog">Changelog</a> for a list of new features.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
${app} is available in the software repositories of the following
|
|
||||||
supported linux distributions:
|
|
||||||
<table id="install_info">
|
|
||||||
<col width="150" /><col width="*" />
|
|
||||||
<tr>
|
|
||||||
<th class="left distro_type">Supported<br/>distributions</th>
|
|
||||||
<th class="right distro_type">Unsupported distributions</th>
|
|
||||||
</tr>
|
|
||||||
<tr class="tdata">
|
|
||||||
<td class="left" style="overflow-y:scroll">
|
|
||||||
<div py:for="distro in supported"
|
|
||||||
style="text-align:center;margin-top:2ex;">
|
|
||||||
<div>
|
|
||||||
<img width="64px" height="64px"
|
|
||||||
src="${distro.img}" alt="${distro.title}" />
|
|
||||||
</div>
|
|
||||||
${distro.title}
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
<td class="right">
|
|
||||||
<div style="margin-left:2em">
|
|
||||||
<h3>Binary install</h3>
|
|
||||||
<p>
|
|
||||||
${app} has a binary installer that has been
|
|
||||||
tested on a number of distributions on both
|
|
||||||
32-bit and 64-bit x86 machines. To install,
|
|
||||||
copy paste the following command into a terminal
|
|
||||||
and press Enter:
|
|
||||||
</p>
|
|
||||||
<pre class="wiki">
|
|
||||||
sudo python -c "import urllib2; exec urllib2.urlopen('http://status.calibre-ebook.com/linux_installer').read(); main()"
|
|
||||||
</pre>
|
|
||||||
<h4>Note</h4>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
When running the command line utilities,
|
|
||||||
they will segfault after completion. This can
|
|
||||||
be ignored.
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
You must have xdg-utils installed
|
|
||||||
on your system before running the installer.
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<h3>Source install</h3>
|
|
||||||
<p>
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
Make sure your system has python ≥ ${dependencies[0][1]}
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Install the various dependencies listed below
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
Run the following commands in a terminal:
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
<pre class="wiki">
|
|
||||||
wget -O- http://status.calibre-ebook.com/dist/src | tar xvz
|
|
||||||
cd calibre*
|
|
||||||
sudo python setup.py install
|
|
||||||
</pre>
|
|
||||||
Note that if your distribution does not have a
|
|
||||||
correctly compiled libunrar.so, ${app} will not
|
|
||||||
support rar files. In order to compile ${app} successfully
|
|
||||||
poppler headers must include XPdf headers. That is, poppler
|
|
||||||
must have been configured with --enable-xpdf-headers. Also,
|
|
||||||
some distributions have buggy libpng headers. See
|
|
||||||
<a href="https://bugs.launchpad.net/ubuntu/+source/libpng/+bug/218409">here</a>
|
|
||||||
for example.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
While you wait for the download to complete, please consider
|
|
||||||
donating to support the development of ${app}.
|
|
||||||
</p>
|
|
||||||
<div>
|
|
||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
|
|
||||||
<input type="hidden" name="cmd" value="_s-xclick" />
|
|
||||||
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
|
|
||||||
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
|
|
||||||
<input type="hidden" name="encrypted" value="-----BEGIN PKCS7-----MIIHbwYJKoZIhvcNAQcEoIIHYDCCB1wCAQExggEwMIIBLAIBADCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwDQYJKoZIhvcNAQEBBQAEgYBn7jneGiSLVO8rcDrBtOUXL+HftY+CiC47hTntwICio6qqpLKezIryyG8tKcjY58Rcocur/kDwljEutIafVG7XRA7BJL9eZdHAZsZdX04f4dApzkWwR9w6GQhj0kwmO2ZNE878UcgGZBve4qQKWM8bf2pMY7vJwCNoo6ozpIi3VTELMAkGBSsOAwIaBQAwgewGCSqGSIb3DQEHATAUBggqhkiG9w0DBwQIBTALt7s1gJmAgcjEAwUMRYeIdIOE/yi0Y5vrVKBFxOUCbqTx/lu3Rk4EHsODZXLHT+BDA5WSWYO3AXfv2Lmlv1kJ7jWrjUVirYoQ5M4qdIhY9DtvPioIMMRoTJmYM9JKH8n2TWcjJ1XIzIuDP4zn8/Ya9hap3RHOrj2RBj89g7iSuFRsjoA0PYZgtWAKwR7g3LLpjRachn041JO55BEd3YWUgorNQeo3WEHgowLFfTWgFFePkm8OoWA1klWkYp4S07IhX5NaRc8OegkdshpkiIHGAKCCA4cwggODMIIC7KADAgECAgEAMA0GCSqGSIb3DQEBBQUAMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTAeFw0wNDAyMTMxMDEzMTVaFw0zNTAyMTMxMDEzMTVaMIGOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxFDASBgNVBAoTC1BheVBhbCBJbmMuMRMwEQYDVQQLFApsaXZlX2NlcnRzMREwDwYDVQQDFAhsaXZlX2FwaTEcMBoGCSqGSIb3DQEJARYNcmVAcGF5cGFsLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwUdO3fxEzEtcnI7ZKZL412XvZPugoni7i7D7prCe0AtaHTc97CYgm7NsAtJyxNLixmhLV8pyIEaiHXWAh8fPKW+R017+EmXrr9EaquPmsVvTywAAE1PMNOKqo2kl4Gxiz9zZqIajOm1fZGWcGS0f5JQ2kBqNbvbg2/Za+GJ/qwUCAwEAAaOB7jCB6zAdBgNVHQ4EFgQUlp98u8ZvF71ZP1LXChvsENZklGswgbsGA1UdIwSBszCBsIAUlp98u8ZvF71ZP1LXChvsENZklGuhgZSkgZEwgY4xCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzEUMBIGA1UEChMLUGF5UGFsIEluYy4xEzARBgNVBAsUCmxpdmVfY2VydHMxETAPBgNVBAMUCGxpdmVfYXBpMRwwGgYJKoZIhvcNAQkBFg1yZUBwYXlwYWwuY29tggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAgV86VpqAWuXvX6Oro4qJ1tYVIT5DgWpE692Ag422H7yRIr/9j/iKG4Thia/Oflx4TdL+IFJBAyPK9v6zZNZtBgPBynXb048hsP16l2vi0k5Q2JKiPDsEfBhGI+HnxLXEaUWAcVfCsQFvd2A1sxRr67ip5y2wwBelUecP3AjJ+YcxggGaMIIBlgIBATCBlDCBjjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MRQwEgYDVQQKEwtQYXlQYWwgSW5jLjETMBEGA1UECxQKbGl2ZV9jZXJ0czERMA8GA1UEAxQIbGl2ZV9hcGkxHDAaBgkqhkiG9w0BCQEWDXJlQHBheXBhbC5jb20CAQAwCQYFKw4DAhoFAKBdMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwHAYJKoZIhvcNAQkFMQ8XDTA4MDQzMDE1MzkyMlowIwYJKoZIhvcNAQkEMRYEFJSI9/zWx7TUlKPY7kLjnvzB1h6sMA0GCSqGSIb3DQEBAQUABIGAikZNCmQdkWPdfmYnGqOb1f65ViaK0zjHf50azvsigWQLlhHqJ3PgB+jEJH3JU9Pm9M4wgiK23Bg2oIGuIsAfQkYO9mw/HjtDtOQHqXyZZbrM32YGtNWUD4ynakLYnaz7OnPl40aTPD4iDApgsGcj1oMdmw7KA2E9J0l2J9iJXF4=-----END PKCS7-----" />
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
<hr/>
|
|
||||||
<h3>Note</h3>
|
|
||||||
<p>
|
|
||||||
If your kernel is compiled with CONFIG_SYSFS_DEPRECATED device detection may not work.
|
|
||||||
</p>
|
|
||||||
<hr/>
|
|
||||||
<h3>Dependencies</h3>
|
|
||||||
${app} has the following dependencies (the listed version is the minimum version)
|
|
||||||
<br/><br/>
|
|
||||||
<table id="dependencies">
|
|
||||||
<tr>
|
|
||||||
<th class="distro_type" style="margin-right:2em">Package</th>
|
|
||||||
<th class="distro_type">Version</th>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="dependency" py:for="dep in dependencies">
|
|
||||||
<td style="margin-right:2em">${dep[0]}</td><td>${dep[1]}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h3>Current calibre versions available in various distros</h3>
|
|
||||||
<div id="osw_calibre"></div>
|
|
||||||
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
|
|
||||||
<script src="http://static.oswatershed.org/js/package_badge.js" type="text/javascript"></script>
|
|
||||||
<script>$(document).ready(function(){ package_badge("calibre", "#osw_calibre"); });</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -1544,7 +1544,7 @@ class Zeroconf(object):
|
|||||||
# This is a quick test to see if we can parse the packets we generate
|
# This is a quick test to see if we can parse the packets we generate
|
||||||
#temp = DNSIncoming(out.packet())
|
#temp = DNSIncoming(out.packet())
|
||||||
try:
|
try:
|
||||||
bytes_sent = self.socket.sendto(out.packet(), 0, (addr, port))
|
self.socket.sendto(out.packet(), 0, (addr, port))
|
||||||
except:
|
except:
|
||||||
# Ignore this, it may be a temporary loss of network connection
|
# Ignore this, it may be a temporary loss of network connection
|
||||||
pass
|
pass
|
||||||
|
@ -65,7 +65,6 @@ def set_translators():
|
|||||||
# CALIBRE_OVERRIDE_LANG=de_DE.utf8 program
|
# CALIBRE_OVERRIDE_LANG=de_DE.utf8 program
|
||||||
lang = get_lang()
|
lang = get_lang()
|
||||||
if lang:
|
if lang:
|
||||||
translations = available_translations()
|
|
||||||
buf = iso639 = None
|
buf = iso639 = None
|
||||||
if os.access(lang+'.po', os.R_OK):
|
if os.access(lang+'.po', os.R_OK):
|
||||||
from calibre.translations.msgfmt import make
|
from calibre.translations.msgfmt import make
|
||||||
|
@ -11,7 +11,7 @@ from calibre.constants import iswindows
|
|||||||
|
|
||||||
def find_executable():
|
def find_executable():
|
||||||
name = 'sigil' + ('.exe' if iswindows else '')
|
name = 'sigil' + ('.exe' if iswindows else '')
|
||||||
path = find_executable_in_path(name)
|
find_executable_in_path(name)
|
||||||
#if path is None and iswindows:
|
#if path is None and iswindows:
|
||||||
# path = search_program_files()
|
# path = search_program_files()
|
||||||
|
|
||||||
|
@ -79,7 +79,6 @@ def save_soup(soup, target):
|
|||||||
|
|
||||||
html = unicode(soup)
|
html = unicode(soup)
|
||||||
with open(target, 'wb') as f:
|
with open(target, 'wb') as f:
|
||||||
idx = html.find('hoping')
|
|
||||||
f.write(html.encode('utf-8'))
|
f.write(html.encode('utf-8'))
|
||||||
|
|
||||||
class response(str):
|
class response(str):
|
||||||
@ -259,7 +258,7 @@ class RecursiveFetcher(object):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
data = self.fetch_url(iurl)
|
data = self.fetch_url(iurl)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
self.log.exception('Could not fetch stylesheet %s'% iurl)
|
self.log.exception('Could not fetch stylesheet %s'% iurl)
|
||||||
continue
|
continue
|
||||||
stylepath = os.path.join(diskpath, 'style'+str(c)+'.css')
|
stylepath = os.path.join(diskpath, 'style'+str(c)+'.css')
|
||||||
@ -282,7 +281,7 @@ class RecursiveFetcher(object):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
data = self.fetch_url(iurl)
|
data = self.fetch_url(iurl)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
self.log.exception('Could not fetch stylesheet %s'% iurl)
|
self.log.exception('Could not fetch stylesheet %s'% iurl)
|
||||||
continue
|
continue
|
||||||
c += 1
|
c += 1
|
||||||
@ -314,7 +313,7 @@ class RecursiveFetcher(object):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
data = self.fetch_url(iurl)
|
data = self.fetch_url(iurl)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
self.log.exception('Could not fetch image %s'% iurl)
|
self.log.exception('Could not fetch image %s'% iurl)
|
||||||
continue
|
continue
|
||||||
c += 1
|
c += 1
|
||||||
@ -443,7 +442,7 @@ class RecursiveFetcher(object):
|
|||||||
|
|
||||||
save_soup(soup, res)
|
save_soup(soup, res)
|
||||||
self.localize_link(tag, 'href', res)
|
self.localize_link(tag, 'href', res)
|
||||||
except Exception, err:
|
except Exception:
|
||||||
self.failed_links.append((iurl, traceback.format_exc()))
|
self.failed_links.append((iurl, traceback.format_exc()))
|
||||||
self.log.exception('Could not fetch link', iurl)
|
self.log.exception('Could not fetch link', iurl)
|
||||||
finally:
|
finally:
|
||||||
|