Allow no cover image in epub
[librarian.git] / librarian / formats / pdf / __init__.py
index 298db09..a994008 100644 (file)
@@ -4,7 +4,6 @@
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 import os
 # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
 #
 import os
-import re
 import shutil
 from subprocess import call, PIPE
 from tempfile import NamedTemporaryFile, mkdtemp
 import shutil
 from subprocess import call, PIPE
 from tempfile import NamedTemporaryFile, mkdtemp
@@ -12,11 +11,11 @@ from lxml import etree
 from urllib import urlretrieve
 from StringIO import StringIO
 from Texml.processor import process
 from urllib import urlretrieve
 from StringIO import StringIO
 from Texml.processor import process
-from librarian import DCNS, XMLNamespace
+from librarian import DCNS, XMLNamespace, BuildError
 from librarian.formats import Format
 from librarian.output import OutputFile
 from librarian.renderers import Register, TreeRenderer
 from librarian.formats import Format
 from librarian.output import OutputFile
 from librarian.renderers import Register, TreeRenderer
-from librarian.utils import Context, get_resource, extend_element
+from librarian.utils import Context, get_resource
 from librarian import core
 from PIL import Image
 from ..html import Silent
 from librarian import core
 from PIL import Image
 from ..html import Silent
@@ -53,7 +52,8 @@ class PdfFormat(Format):
 
     def add_file(self, ctx, filename, url=None, path=None, image=False):
         from subprocess import call
 
     def add_file(self, ctx, filename, url=None, path=None, image=False):
         from subprocess import call
-        assert url or path
+        if not url and not path:
+            raise BuildError('No URL or path for image')
         save_as = os.path.join(ctx.workdir, filename)
         if path is not None:
             ext = path.rsplit('.', 1)[-1]
         save_as = os.path.join(ctx.workdir, filename)
         if path is not None:
             ext = path.rsplit('.', 1)[-1]
@@ -73,6 +73,8 @@ class PdfFormat(Format):
             if url.startswith('/'):
                 url = 'http://milpeer.eu' + url
 
             if url.startswith('/'):
                 url = 'http://milpeer.eu' + url
 
+            if '.' not in url:
+                raise BuildError('Linked file without extension: %s' % url)
             ext = url.rsplit('.', 1)[-1]
             if image:
                 urlretrieve(url, save_as + '_.' + ext)
             ext = url.rsplit('.', 1)[-1]
             if image:
                 urlretrieve(url, save_as + '_.' + ext)
@@ -80,7 +82,8 @@ class PdfFormat(Format):
                     call(['convert', save_as + '_.' + ext, save_as])
                 else:
                     # JPEGs with bad density will break LaTeX with 'Dimension too large'.
                     call(['convert', save_as + '_.' + ext, save_as])
                 else:
                     # JPEGs with bad density will break LaTeX with 'Dimension too large'.
-                    r = call(['convert', '-units', 'PixelsPerInch', save_as + '_.' + ext, '-density', '300', save_as + '_2.' + ext])
+                    r = call(['convert', '-units', 'PixelsPerInch', save_as + '_.' + ext, '-density', '300',
+                              save_as + '_2.' + ext])
                     if r:
                         shutil.move(save_as + '_.' + ext, save_as)
                     else:
                     if r:
                         shutil.move(save_as + '_.' + ext, save_as)
                     else:
@@ -124,7 +127,7 @@ class PdfFormat(Format):
             img = Image.open(self.get_file(build_ctx, 'cover.png'))
             size = img.size
 
             img = Image.open(self.get_file(build_ctx, 'cover.png'))
             size = img.size
 
-            if (size[1] > size[0]):
+            if size[1] > size[0]:
                 img = img.crop((0, 0, size[0], size[0]))
                 img.save(self.get_file(build_ctx, 'cover.png'), format=img.format, quality=90)
             size = img.size
                 img = img.crop((0, 0, size[0], size[0]))
                 img.save(self.get_file(build_ctx, 'cover.png'), format=img.format, quality=90)
             size = img.size
@@ -146,14 +149,14 @@ class PdfFormat(Format):
             p[0].append(texml_cmd("noindent"))
             p[0].append(texml_cmd("nohyphens", author))
             p[0].append(texml_cmd("vspace", "1em"))
             p[0].append(texml_cmd("noindent"))
             p[0].append(texml_cmd("nohyphens", author))
             p[0].append(texml_cmd("vspace", "1em"))
-            #p[0][-1].tail = author
+            # p[0][-1].tail = author
         if title:
             p = texml_cmd("par", "")
             grp.append(p)
             p[0].append(texml_cmd("Huge"))
             p[0].append(texml_cmd("noindent"))
             p[0].append(texml_cmd("nohyphens", title))
         if title:
             p = texml_cmd("par", "")
             grp.append(p)
             p[0].append(texml_cmd("Huge"))
             p[0].append(texml_cmd("noindent"))
             p[0].append(texml_cmd("nohyphens", title))
-            #p[0][-1].tail = title
+            # p[0][-1].tail = title
         doc.append(texml_cmd("vfill"))
         doc.append(texml_cmd("vfill"))
 
         doc.append(texml_cmd("vfill"))
         doc.append(texml_cmd("vfill"))
 
@@ -161,7 +164,7 @@ class PdfFormat(Format):
         cover_logo_url = getattr(build_ctx, 'cover_logo', None)
         # TEST
         # TODO: convert
         cover_logo_url = getattr(build_ctx, 'cover_logo', None)
         # TEST
         # TODO: convert
-        #cover_logo_url = 'http://milpeer.mdrn.pl/media/dynamic/people/logo/nowoczesnapolska.org.pl.png'
+        # cover_logo_url = 'http://milpeer.mdrn.pl/media/dynamic/people/logo/nowoczesnapolska.org.pl.png'
         if cover_logo_url:
             self.add_file(build_ctx, 'coverlogo.png', cover_logo_url, image=True)
             size = Image.open(self.get_file(build_ctx, 'coverlogo.png')).size
         if cover_logo_url:
             self.add_file(build_ctx, 'coverlogo.png', cover_logo_url, image=True)
             size = Image.open(self.get_file(build_ctx, 'coverlogo.png')).size
@@ -183,11 +186,10 @@ class PdfFormat(Format):
         doc.append(texml_cmd("vspace", "1em"))
 
         for m, f in (
         doc.append(texml_cmd("vspace", "1em"))
 
         for m, f in (
-            ('Publisher: ', DCNS('publisher')),
-            ('Rights: ', DCNS('rights')),
-            ('Intended audience: ', DCNS('audience')),
-            ('', DCNS('description')),
-            ):
+                ('Publisher: ', DCNS('publisher')),
+                ('Rights: ', DCNS('rights')),
+                ('Intended audience: ', DCNS('audience')),
+                ('', DCNS('description'))):
             v = self.doc.meta.get_one(f)
             if v:
                 e = texml_cmd("par", "")
             v = self.doc.meta.get_one(f)
             if v:
                 e = texml_cmd("par", "")
@@ -196,7 +198,6 @@ class PdfFormat(Format):
                 doc.append(e)
                 doc.append(texml_cmd("vspace", "1em"))
 
                 doc.append(e)
                 doc.append(texml_cmd("vspace", "1em"))
 
-
         e = texml_cmd("par", "")
         e[0].append(texml_cmd("noindent"))
         e[0][0].tail = "Resource prepared using "
         e = texml_cmd("par", "")
         e[0].append(texml_cmd("noindent"))
         e[0][0].tail = "Resource prepared using "
@@ -205,7 +206,7 @@ class PdfFormat(Format):
         doc.append(e)
 
         source_url = getattr(build_ctx, 'source_url', None)
         doc.append(e)
 
         source_url = getattr(build_ctx, 'source_url', None)
-        #source_url = 'http://milpeer.mdrn.pl/documents/27/'
+        # source_url = 'http://milpeer.mdrn.pl/documents/27/'
         if source_url:
             e = texml_cmd("par", "")
             doc.append(e)
         if source_url:
             e = texml_cmd("par", "")
             doc.append(e)
@@ -220,16 +221,14 @@ class PdfFormat(Format):
         texml = self.get_texml(ctx)
         tex_path = os.path.join(ctx.workdir, 'doc.tex')
         with open(tex_path, 'w') as fout:
         texml = self.get_texml(ctx)
         tex_path = os.path.join(ctx.workdir, 'doc.tex')
         with open(tex_path, 'w') as fout:
-            #print etree.tostring(texml)
+            # print etree.tostring(texml)
             process(StringIO(etree.tostring(texml)), fout, 'utf-8')
 
             process(StringIO(etree.tostring(texml)), fout, 'utf-8')
 
-        #~ if self.save_tex:
-            #~ shutil.copy(tex_path, self.save_tex)
-
-
+        # if self.save_tex:
+        #     shutil.copy(tex_path, self.save_tex)
 
 
-        #for sfile in ['wasysym.sty', 'uwasyvar.fd', 'uwasy.fd']:
-        #    shutil.copy(get_resource(os.path.join('res/wasysym', sfile)), temp)
+        # for sfile in ['wasysym.sty', 'uwasyvar.fd', 'uwasy.fd']:
+        #     shutil.copy(get_resource(os.path.join('res/wasysym', sfile)), temp)
         return ctx.workdir
 
     def build(self, ctx=None, verbose=False):
         return ctx.workdir
 
     def build(self, ctx=None, verbose=False):
@@ -247,9 +246,9 @@ class PdfFormat(Format):
         else:
             for i in range(self.tex_passes):
                 p = call(['xelatex', '-interaction=batchmode', tex_path],
         else:
             for i in range(self.tex_passes):
                 p = call(['xelatex', '-interaction=batchmode', tex_path],
-                            stdout=PIPE, stderr=PIPE)
+                         stdout=PIPE, stderr=PIPE)
         if p:
         if p:
-            #raise ParseError("Error parsing .tex file: %s" % tex_path)
+            # raise ParseError("Error parsing .tex file: %s" % tex_path)
             raise RuntimeError("Error parsing .tex file: %s" % tex_path)
 
         if cwd is not None:
             raise RuntimeError("Error parsing .tex file: %s" % tex_path)
 
         if cwd is not None:
@@ -266,23 +265,24 @@ class PdfFormat(Format):
         return self.renderers.get_for(element).render(element, ctx)
 
 
         return self.renderers.get_for(element).render(element, ctx)
 
 
-
-
 class CmdRenderer(TreeRenderer):
     def parms(self):
         return []
 class CmdRenderer(TreeRenderer):
     def parms(self):
         return []
+
     def container(self):
         root = etree.Element(self.root_name)
         root.append(texml_cmd(self.tag_name, *(self.parms() + [""])))
         inner = root[0][-1]
         return root, inner
 
     def container(self):
         root = etree.Element(self.root_name)
         root.append(texml_cmd(self.tag_name, *(self.parms() + [""])))
         inner = root[0][-1]
         return root, inner
 
+
 class EnvRenderer(TreeRenderer):
     def container(self):
         root = etree.Element(self.root_name)
         inner = etree.SubElement(root, 'env', name=self.tag_name)
         return root, inner
 
 class EnvRenderer(TreeRenderer):
     def container(self):
         root = etree.Element(self.root_name)
         inner = etree.SubElement(root, 'env', name=self.tag_name)
         return root, inner
 
+
 class GroupRenderer(CmdRenderer):
     def container(self):
         root = etree.Element(self.root_name)
 class GroupRenderer(CmdRenderer):
     def container(self):
         root = etree.Element(self.root_name)
@@ -311,6 +311,7 @@ PdfFormat.renderers.register(core.Header, None, CmdRenderer('section*'))
 
 PdfFormat.renderers.register(core.Div, None, CmdRenderer('par'))
 
 
 PdfFormat.renderers.register(core.Div, None, CmdRenderer('par'))
 
+
 class ImgRenderer(CmdRenderer):
     def parms(self):
         return ["", ""]
 class ImgRenderer(CmdRenderer):
     def parms(self):
         return ["", ""]
@@ -324,8 +325,8 @@ class ImgRenderer(CmdRenderer):
         root[0][0].text = 'f%d.png' % nr
         try:
             size = Image.open(ctx.format.get_file(ctx, 'f%d.png' % nr)).size
         root[0][0].text = 'f%d.png' % nr
         try:
             size = Image.open(ctx.format.get_file(ctx, 'f%d.png' % nr)).size
-        except IOError: # not an image
-            del root[0];
+        except IOError:  # not an image
+            del root[0]
             return root
         root[0][1].text = '15cm'
         root[0][2].text = '%fcm' % (15.0 * size[1] / size[0])
             return root
         root[0][1].text = '15cm'
         root[0][2].text = '%fcm' % (15.0 * size[1] / size[0])
@@ -334,27 +335,41 @@ class ImgRenderer(CmdRenderer):
 PdfFormat.renderers.register(core.Div, 'img', ImgRenderer('insertimage'))
 
 
 PdfFormat.renderers.register(core.Div, 'img', ImgRenderer('insertimage'))
 
 
+class VideoRenderer(CmdRenderer):
+    def render(self, element, ctx):
+        root = super(VideoRenderer, self).render(element, ctx)
+        url = 'https://www.youtube.com/watch?v=%s' % element.attrib.get('videoid')
+        link = texml_cmd('href', url, url)
+        root[0][0].text = None
+        root[0][0].append(link)
+        return root
+
+PdfFormat.renderers.register(core.Div, 'video', VideoRenderer('par'))
+
+
 PdfFormat.renderers.register(core.Div, 'defined', CmdRenderer('textbf'))
 PdfFormat.renderers.register(core.Div, 'item', CmdRenderer('item'))
 PdfFormat.renderers.register(core.Div, 'defined', CmdRenderer('textbf'))
 PdfFormat.renderers.register(core.Div, 'item', CmdRenderer('item'))
+PdfFormat.renderers.register(core.Span, 'item', CmdRenderer('item'))
 PdfFormat.renderers.register(core.Div, 'list', EnvRenderer('itemize'))
 PdfFormat.renderers.register(core.Div, 'list.enum', EnvRenderer('enumerate'))
 
 
 PdfFormat.renderers.register(core.Div, 'list', EnvRenderer('itemize'))
 PdfFormat.renderers.register(core.Div, 'list.enum', EnvRenderer('enumerate'))
 
 
-
 PdfFormat.renderers.register(core.Span, None, TreeRenderer())
 PdfFormat.renderers.register(core.Span, 'cite', CmdRenderer('emph'))
 PdfFormat.renderers.register(core.Span, 'cite.code', CmdRenderer('texttt'))
 PdfFormat.renderers.register(core.Span, 'emp', CmdRenderer('textbf'))
 PdfFormat.renderers.register(core.Span, 'emph', CmdRenderer('emph'))
 
 PdfFormat.renderers.register(core.Span, None, TreeRenderer())
 PdfFormat.renderers.register(core.Span, 'cite', CmdRenderer('emph'))
 PdfFormat.renderers.register(core.Span, 'cite.code', CmdRenderer('texttt'))
 PdfFormat.renderers.register(core.Span, 'emp', CmdRenderer('textbf'))
 PdfFormat.renderers.register(core.Span, 'emph', CmdRenderer('emph'))
 
+
 class SpanUri(CmdRenderer):
     def parms(self):
         return [""]
 class SpanUri(CmdRenderer):
     def parms(self):
         return [""]
+
     def render(self, element, ctx):
         root = super(SpanUri, self).render(element, ctx)
         src = element.text
         if src.startswith('file://'):
     def render(self, element, ctx):
         root = super(SpanUri, self).render(element, ctx)
         src = element.text
         if src.startswith('file://'):
-           src = ctx.files_path + src[7:]
+            src = ctx.files_path + src[7:]
         root[0][0].text = src
         return root
 PdfFormat.renderers.register(core.Span, 'uri', SpanUri('href'))
         root[0][0].text = src
         return root
 PdfFormat.renderers.register(core.Span, 'uri', SpanUri('href'))
@@ -363,19 +378,17 @@ PdfFormat.renderers.register(core.Span, 'uri', SpanUri('href'))
 class SpanLink(CmdRenderer):
     def parms(self):
         return [""]
 class SpanLink(CmdRenderer):
     def parms(self):
         return [""]
+
     def render(self, element, ctx):
         root = super(SpanLink, self).render(element, ctx)
         src = element.attrib.get('href', '')
         if src.startswith('file://'):
     def render(self, element, ctx):
         root = super(SpanLink, self).render(element, ctx)
         src = element.attrib.get('href', '')
         if src.startswith('file://'):
-           src = ctx.files_path + src[7:]
+            src = ctx.files_path + src[7:]
         root[0][0].text = src
         return root
 PdfFormat.renderers.register(core.Span, 'link', SpanLink('href'))
 
 
         root[0][0].text = src
         return root
 PdfFormat.renderers.register(core.Span, 'link', SpanLink('href'))
 
 
-
-
 PdfFormat.renderers.register(core.Aside, None, TreeRenderer())
 PdfFormat.renderers.register(core.Aside, 'editorial', CmdRenderer('editorialpage'))
 PdfFormat.renderers.register(core.Aside, 'comment', Silent())
 PdfFormat.renderers.register(core.Aside, None, TreeRenderer())
 PdfFormat.renderers.register(core.Aside, 'editorial', CmdRenderer('editorialpage'))
 PdfFormat.renderers.register(core.Aside, 'comment', Silent())
-