diff --git a/setup/resources.py b/setup/resources.py
index 87f4c645c4..0e91a9faa7 100644
--- a/setup/resources.py
+++ b/setup/resources.py
@@ -6,7 +6,7 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal '
__docformat__ = 'restructuredtext en'
-import os, cPickle, re, shutil, marshal, zipfile, glob, time
+import os, cPickle, re, shutil, marshal, zipfile, glob, time, subprocess, sys
from zlib import compress
from setup import Command, basenames, __appname__
@@ -35,8 +35,8 @@ class Coffee(Command): # {{{
help='Display the generated javascript')
def run(self, opts):
- from calibre.utils.coffeescript import compile_coffeescript
- self.compiler = compile_coffeescript
+ cc = self.j(self.SRC, 'calibre', 'utils', 'serve_coffee.py')
+ self.compiler = [sys.executable, cc, 'compile']
self.do_coffee_compile(opts)
if opts.watch:
try:
@@ -63,24 +63,24 @@ class Coffee(Command): # {{{
if self.newer(js, x):
print ('\t%sCompiling %s'%(time.strftime('[%H:%M:%S] ') if
timestamp else '', os.path.basename(x)))
- with open(x, 'rb') as f:
- cs, errs = self.compiler(f.read())
- for line in errs:
- print (line)
- if cs and not errs:
+ try:
+ cs = subprocess.check_output(self.compiler +
+ [x]).decode('utf-8')
+ except Exception as e:
+ print ('\n\tCompilation of %s failed'%os.path.basename(x))
+ print (e)
+ if ignore_errors:
+ with open(js, 'wb') as f:
+ f.write('# Compilation from coffeescript failed')
+ else:
+ raise SystemExit(1)
+ else:
with open(js, 'wb') as f:
f.write(cs.encode('utf-8'))
if opts.show_js:
self.show_js(js)
print ('#'*80)
print ('#'*80)
- else:
- print ('\n\tCompilation of %s failed'%os.path.basename(x))
- if ignore_errors:
- with open(js, 'wb') as f:
- f.write('# Compilation from coffeescript failed')
- else:
- raise SystemExit(1)
def clean(self):
for toplevel, dest in self.COFFEE_DIRS.iteritems():
diff --git a/src/calibre/__init__.py b/src/calibre/__init__.py
index 2ed2173d87..f17b909ea7 100644
--- a/src/calibre/__init__.py
+++ b/src/calibre/__init__.py
@@ -31,7 +31,7 @@ if False:
# Prevent pyflakes from complaining
winutil, winutilerror, __appname__, islinux, __version__
fcntl, win32event, isfrozen, __author__
- winerror, win32api, isbsd
+ winerror, win32api, isbsd, config_dir
_mt_inited = False
def _init_mimetypes():
@@ -699,69 +699,6 @@ if isosx:
traceback.print_exc()
def ipython(user_ns=None):
- old_argv = sys.argv
- sys.argv = ['ipython']
- if user_ns is None:
- user_ns = locals()
- ipydir = os.path.join(config_dir, ('_' if iswindows else '.')+'ipython')
- os.environ['IPYTHONDIR'] = ipydir
- if not os.path.exists(ipydir):
- os.makedirs(ipydir)
- for x in ('', '.ini'):
- rc = os.path.join(ipydir, 'ipythonrc'+x)
- if not os.path.exists(rc):
- open(rc, 'wb').write(' ')
- UC = '''
-import IPython.ipapi
-ip = IPython.ipapi.get()
-
-# You probably want to uncomment this if you did %upgrade -nolegacy
-import ipy_defaults
-
-import os, re, sys
-
-def main():
- # Handy tab-completers for %cd, %run, import etc.
- # Try commenting this out if you have completion problems/slowness
- import ipy_stock_completers
-
- # uncomment if you want to get ipython -p sh behaviour
- # without having to use command line switches
-
- import ipy_profile_sh
-
-
- # Configure your favourite editor?
- # Good idea e.g. for %edit os.path.isfile
-
- import ipy_editors
-
- # Choose one of these:
-
- #ipy_editors.scite()
- #ipy_editors.scite('c:/opt/scite/scite.exe')
- #ipy_editors.komodo()
- #ipy_editors.idle()
- # ... or many others, try 'ipy_editors??' after import to see them
-
- # Or roll your own:
- #ipy_editors.install_editor("c:/opt/jed +$line $file")
-
- ipy_editors.kate()
-
- o = ip.options
- # An example on how to set options
- #o.autocall = 1
- o.system_verbose = 0
- o.confirm_exit = 0
-
-main()
- '''
- uc = os.path.join(ipydir, 'ipy_user_conf.py')
- if not os.path.exists(uc):
- open(uc, 'wb').write(UC)
- from IPython.Shell import IPShellEmbed
- ipshell = IPShellEmbed(user_ns=user_ns)
- ipshell()
- sys.argv = old_argv
+ from calibre.utils.ipython import ipython
+ ipython(user_ns=user_ns)
diff --git a/src/calibre/constants.py b/src/calibre/constants.py
index 0b50c7d2ac..2170db4587 100644
--- a/src/calibre/constants.py
+++ b/src/calibre/constants.py
@@ -153,3 +153,12 @@ else:
atexit.register(cleanup_cdir)
# }}}
+def get_version():
+ '''Return version string that indicates if we are running in a dev env'''
+ dv = os.environ.get('CALIBRE_DEVELOP_FROM', None)
+ v = __version__
+ if getattr(sys, 'frozen', False) and dv and os.path.abspath(dv) in sys.path:
+ v += '*'
+ return v
+
+
diff --git a/src/calibre/devices/eb600/driver.py b/src/calibre/devices/eb600/driver.py
index f12b616452..ea2a41c0b7 100644
--- a/src/calibre/devices/eb600/driver.py
+++ b/src/calibre/devices/eb600/driver.py
@@ -95,11 +95,11 @@ class POCKETBOOK360(EB600):
FORMATS = ['epub', 'fb2', 'prc', 'mobi', 'pdf', 'djvu', 'rtf', 'chm', 'txt']
- VENDOR_NAME = ['PHILIPS', '__POCKET']
- WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['MASS_STORGE', 'BOOK_USB_STORAGE']
+ VENDOR_NAME = ['PHILIPS', '__POCKET', 'POCKETBO']
+ WINDOWS_MAIN_MEM = WINDOWS_CARD_A_MEM = ['MASS_STORGE', 'BOOK_USB_STORAGE',
+ 'POCKET_611_61']
- OSX_MAIN_MEM = 'Philips Mass Storge Media'
- OSX_CARD_A_MEM = 'Philips Mass Storge Media'
+ OSX_MAIN_MEM = OSX_CARD_A_MEM = 'Philips Mass Storge Media'
OSX_MAIN_MEM_VOL_PAT = re.compile(r'/Pocket')
@classmethod
diff --git a/src/calibre/ebooks/mobi/mobiml.py b/src/calibre/ebooks/mobi/mobiml.py
index 479afa3d06..7cda4b0a57 100644
--- a/src/calibre/ebooks/mobi/mobiml.py
+++ b/src/calibre/ebooks/mobi/mobiml.py
@@ -568,7 +568,11 @@ class MobiMLizer(object):
if isblock:
para = bstate.para
if para is not None and para.text == u'\xa0' and len(para) < 1:
- para.getparent().replace(para, etree.Element(XHTML('br')))
+ if style.height > 2:
+ para.getparent().replace(para, etree.Element(XHTML('br')))
+ else:
+ # This is too small to be rendered effectively, drop it
+ para.getparent().remove(para)
bstate.para = None
bstate.istate = None
vmargin = asfloat(style['margin-bottom'])
diff --git a/src/calibre/ebooks/mobi/reader.py b/src/calibre/ebooks/mobi/reader.py
index c0a1687eaf..e664834260 100644
--- a/src/calibre/ebooks/mobi/reader.py
+++ b/src/calibre/ebooks/mobi/reader.py
@@ -244,7 +244,9 @@ class MetadataHeader(BookHeader):
class MobiReader(object):
- PAGE_BREAK_PAT = re.compile(r'(<[/]{0,1}mbp:pagebreak\s*[/]{0,1}>)+', re.IGNORECASE)
+ PAGE_BREAK_PAT = re.compile(
+ r'<\s*/{0,1}\s*mbp:pagebreak((?:\s+[^/>]*){0,1})/{0,1}\s*>\s*(?:<\s*/{0,1}\s*mbp:pagebreak\s*/{0,1}\s*>)*',
+ re.IGNORECASE)
IMAGE_ATTRS = ('lowrecindex', 'recindex', 'hirecindex')
def __init__(self, filename_or_stream, log, user_encoding=None, debug=None,
@@ -539,6 +541,9 @@ class MobiReader(object):
x.getparent().remove(x)
svg_tags = []
forwardable_anchors = []
+ pagebreak_anchors = []
+ BLOCK_TAGS = {'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
+ 'div', 'p'}
for i, tag in enumerate(root.iter(etree.Element)):
tag.attrib.pop('xmlns', '')
for x in tag.attrib:
@@ -657,6 +662,10 @@ class MobiReader(object):
if not tag.text:
tag.tag = 'div'
+ if (attrib.get('class', None) == 'mbp_pagebreak' and tag.tag ==
+ 'div' and 'filepos-id' in attrib):
+ pagebreak_anchors.append(tag)
+
if 'filepos-id' in attrib:
attrib['id'] = attrib.pop('filepos-id')
if 'name' in attrib and attrib['name'] != attrib['id']:
@@ -670,8 +679,7 @@ class MobiReader(object):
if (tag.tag == 'a' and attrib.get('id', '').startswith('filepos')
and not tag.text and (tag.tail is None or not
tag.tail.strip()) and getattr(tag.getnext(), 'tag',
- None) in ('h1', 'h2', 'h3', 'h4', 'h5', 'h6',
- 'div', 'p')):
+ None) in BLOCK_TAGS):
# This is an empty anchor immediately before a block tag, move
# the id onto the block tag instead
forwardable_anchors.append(tag)
@@ -704,6 +712,18 @@ class MobiReader(object):
if hasattr(parent, 'remove'):
parent.remove(tag)
+ for tag in pagebreak_anchors:
+ anchor = tag.attrib['id']
+ del tag.attrib['id']
+ if 'name' in tag.attrib:
+ del tag.attrib['name']
+ p = tag.getparent()
+ a = p.makeelement('a')
+ a.attrib['id'] = anchor
+ p.insert(p.index(tag)+1, a)
+ if getattr(a.getnext(), 'tag', None) in BLOCK_TAGS:
+ forwardable_anchors.append(a)
+
for tag in forwardable_anchors:
block = tag.getnext()
tag.getparent().remove(tag)
@@ -919,7 +939,7 @@ class MobiReader(object):
def replace_page_breaks(self):
self.processed_html = self.PAGE_BREAK_PAT.sub(
- '',
+ r'',
self.processed_html)
def add_anchors(self):
@@ -1047,3 +1067,22 @@ def get_metadata(stream):
im.convert('RGB').save(obuf, format='JPEG')
mi.cover_data = ('jpg', obuf.getvalue())
return mi
+
+def test_mbp_regex():
+ for raw, m in {
+ '':'',
+ 'yyy':' xxxyyy',
+ ' ':'',
+ 'xxx':'xxx',
+ 'xxx':'xxx',
+ 'xxx':' sdfxxx',
+ '':' ',
+ '':'',
+ '':' sdf',
+ 'xxx':'xxx',
+ }.iteritems():
+ ans = MobiReader.PAGE_BREAK_PAT.sub(r'\1', raw)
+ if ans != m:
+ raise Exception('%r != %r for %r'%(ans, m, raw))
+
+
diff --git a/src/calibre/ebooks/oeb/display/test-cfi/birds.mp4 b/src/calibre/ebooks/oeb/display/test-cfi/birds.mp4
deleted file mode 100644
index 54869c714a..0000000000
Binary files a/src/calibre/ebooks/oeb/display/test-cfi/birds.mp4 and /dev/null differ
diff --git a/src/calibre/ebooks/oeb/display/test-cfi/birds.webm b/src/calibre/ebooks/oeb/display/test-cfi/birds.webm
new file mode 100644
index 0000000000..ea2dcf4d0f
Binary files /dev/null and b/src/calibre/ebooks/oeb/display/test-cfi/birds.webm differ
diff --git a/src/calibre/ebooks/oeb/display/test-cfi/cfi-test.coffee b/src/calibre/ebooks/oeb/display/test-cfi/cfi-test.coffee
index b9b2b7f5d6..b259636722 100644
--- a/src/calibre/ebooks/oeb/display/test-cfi/cfi-test.coffee
+++ b/src/calibre/ebooks/oeb/display/test-cfi/cfi-test.coffee
@@ -32,6 +32,11 @@ window_ypos = (pos=null) ->
mark_and_reload = (evt) ->
# Remove image in case the click was on the image itself, we want the cfi to
# be on the underlying element
+ if evt.button == 2
+ return # Right mouse click, generated only in firefox
+ reset = document.getElementById('reset')
+ if document.elementFromPoint(evt.clientX, evt.clientY) == reset
+ return
ms = document.getElementById("marker")
if ms
ms.parentNode?.removeChild(ms)
diff --git a/src/calibre/ebooks/oeb/display/test-cfi/index.html b/src/calibre/ebooks/oeb/display/test-cfi/index.html
index 962b14e628..53d84de0c7 100644
--- a/src/calibre/ebooks/oeb/display/test-cfi/index.html
+++ b/src/calibre/ebooks/oeb/display/test-cfi/index.html
@@ -71,7 +71,8 @@
righteous indignation and dislike men who are so beguiled and
demoralized by the charms of pleasure of the moment, so blinded
by desire, that they cannot foresee
-
+
Some entities and comments
@@ -103,7 +104,8 @@
they cannot foresee
Lots of collapsed whitespace
- Try clicking the A character after the colon: A suffix
+ Try clicking the A character after the colon:
+ A suffix
Lots of nested/sibling tags
A bunch of nested and sibling
@@ -111,20 +113,23 @@
over this paragraph to test things.
Images
- Try clicking at different points along the image. Also try changing the magnification and then hitting reload.
-
+ Try clicking at different points along the image. Also try
+ changing the magnification and then hitting reload.
+
Video
Try clicking on this video while it is playing. The page should
reload with the video paused at the point it was at when you
clicked. To play the video you should right click on it and select
- play (otherwise the click will cause a reload). This is currently
- broken because of issues in the python server use to serve test
- content. I lack the patience to track down the bug.
-
+ play (otherwise the click will cause a reload).
+
+
-
+