Merge recent changes from branch 'fnp/librarian/master'
authorRobert Błaut <listy@blaut.biz>
Sat, 15 Feb 2014 09:52:13 +0000 (10:52 +0100)
committerRobert Błaut <listy@blaut.biz>
Sat, 15 Feb 2014 09:52:13 +0000 (10:52 +0100)
Sync between fork and origin

22 files changed:
librarian/__init__.py
librarian/cover.py
librarian/dcparser.py
librarian/html.py
librarian/pdf.py
librarian/pdf/wl.cls
librarian/pdf/wl2tex.xslt
librarian/res/sponsors/nck.png [new file with mode: 0644]
librarian/res/webtreatsetc-5647576127-ccby.png [deleted file]
librarian/sponsor.py [new file with mode: 0644]
librarian/text.py
scripts/book2cover
scripts/book2html
scripts/book2pdf
scripts/book2txt
setup.py
tests/files/text/asnyk_miedzy_nami_expected.html
tests/files/text/asnyk_miedzy_nami_fragments.html [new file with mode: 0644]
tests/files/text/asnyk_zbior.xml [changed mode: 0755->0644]
tests/files/text/do-mlodych.xml [changed mode: 0755->0644]
tests/files/text/miedzy-nami-nic-nie-bylo.xml
tests/test_html_fragments.py [new file with mode: 0644]

index bf15d13..b257b79 100644 (file)
@@ -72,6 +72,7 @@ XINS = XMLNamespace("http://www.w3.org/2001/XInclude")
 XHTMLNS = XMLNamespace("http://www.w3.org/1999/xhtml")
 NCXNS = XMLNamespace("http://www.daisy.org/z3986/2005/ncx/")
 OPFNS = XMLNamespace("http://www.idpf.org/2007/opf")
 XHTMLNS = XMLNamespace("http://www.w3.org/1999/xhtml")
 NCXNS = XMLNamespace("http://www.daisy.org/z3986/2005/ncx/")
 OPFNS = XMLNamespace("http://www.idpf.org/2007/opf")
+PLMETNS = XMLNamespace("http://dl.psnc.pl/schemas/plmet/")
 
 WLNS = EmptyNamespace()
 
 
 WLNS = EmptyNamespace()
 
index d1b2cc0..2f3117c 100644 (file)
@@ -248,9 +248,11 @@ class WLCover(Cover):
     logo_width = 140
 
     bar_width = 35
     logo_width = 140
 
     bar_width = 35
+    bar_color = '#000'
+    box_position = 'middle'
     background_color = '#444'
     author_color = '#444'
     background_color = '#444'
     author_color = '#444'
-    default_background = get_resource('res/cover.png')
+    background_img = get_resource('res/cover.png')
     format = 'JPEG'
 
     epoch_colors = {
     format = 'JPEG'
 
     epoch_colors = {
@@ -266,11 +268,25 @@ class WLCover(Cover):
         u'Współczesność': '#06393d',
     }
 
         u'Współczesność': '#06393d',
     }
 
-    def __init__(self, book_info, format=None, width=None, height=None, with_logo=False):
+    kind_box_position = {
+        u'Liryka': 'top',
+        u'Epika': 'bottom',
+    }
+
+    def __init__(self, book_info, format=None, width=None, height=None):
         super(WLCover, self).__init__(book_info, format=format, width=width, height=height)
         super(WLCover, self).__init__(book_info, format=format, width=width, height=height)
-        self.kind = book_info.kind
-        self.epoch = book_info.epoch
-        self.with_logo = with_logo
+        # Set box position.
+        self.box_position = book_info.cover_box_position or \
+            self.kind_box_position.get(book_info.kind, self.box_position)
+        # Set bar color.
+        if book_info.cover_bar_color == 'none':
+            self.bar_width = 0
+        else:
+            self.bar_color = book_info.cover_bar_color or \
+                self.epoch_colors.get(book_info.epoch, self.bar_color)
+        # Set title color.
+        self.title_color = self.epoch_colors.get(book_info.epoch, self.title_color)
+
         if book_info.cover_url:
             url = book_info.cover_url
             bg_src = None
         if book_info.cover_url:
             url = book_info.cover_url
             bg_src = None
@@ -278,46 +294,17 @@ class WLCover(Cover):
                 bg_src = URLOpener().open(url)
             self.background_img = StringIO(bg_src.read())
             bg_src.close()
                 bg_src = URLOpener().open(url)
             self.background_img = StringIO(bg_src.read())
             bg_src.close()
-        else:
-            self.background_img = self.default_background
 
     def pretty_author(self):
         return self.author.upper()
 
 
     def pretty_author(self):
         return self.author.upper()
 
-    def image(self):
-        metr = Metric(self, self.scale)
-        img = Image.new('RGB', (metr.width, metr.height), self.background_color)
-        draw = ImageDraw.Draw(img)
-
-        if self.epoch in self.epoch_colors:
-            epoch_color = self.epoch_colors[self.epoch]
-        else:
-            epoch_color = '#000'
-        draw.rectangle((0, 0, metr.bar_width, metr.height), fill=epoch_color)
-
-        if self.background_img:
-            src = Image.open(self.background_img)
-            trg_size = (metr.width - metr.bar_width, metr.height)
-            if src.size[0] * trg_size[1] < src.size[1] * trg_size[0]:
-                resized = (
-                    trg_size[0],
-                    src.size[1] * trg_size[0] / src.size[0]
-                )
-                cut = (resized[1] - trg_size[1]) / 2
-                src = src.resize(resized, Image.ANTIALIAS)
-                src = src.crop((0, cut, src.size[0], src.size[1] - cut))
-            else:
-                resized = (
-                    src.size[0] * trg_size[1] / src.size[1],
-                    trg_size[1],
-                )
-                cut = (resized[0] - trg_size[0]) / 2
-                src = src.resize(resized, Image.ANTIALIAS)
-                src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))
+    def add_box(self, img):
+        if self.box_position == 'none':
+            return img
 
 
-            img.paste(src, (metr.bar_width, 0))
-            del src
+        metr = Metric(self, self.scale)
 
 
+        # Write author name.
         box = TextBox(metr.title_box_width, metr.height, padding_y=metr.box_padding_y)
         author_font = ImageFont.truetype(
             self.author_font_ttf, metr.author_font_size)
         box = TextBox(metr.title_box_width, metr.height, padding_y=metr.box_padding_y)
         author_font = ImageFont.truetype(
             self.author_font_ttf, metr.author_font_size)
@@ -333,46 +320,68 @@ class WLCover(Cover):
                 fill=self.author_color, width=metr.box_line_width)
         box.skip(metr.box_below_line)
 
                 fill=self.author_color, width=metr.box_line_width)
         box.skip(metr.box_below_line)
 
+        # Write title.
         title_font = ImageFont.truetype(
             self.title_font_ttf, metr.title_font_size)
         box.text(self.pretty_title(),
                  line_height=metr.title_lineskip,
                  font=title_font,
         title_font = ImageFont.truetype(
             self.title_font_ttf, metr.title_font_size)
         box.text(self.pretty_title(),
                  line_height=metr.title_lineskip,
                  font=title_font,
-                 color=epoch_color,
+                 color=self.title_color,
                  shadow_color=self.title_shadow,
                 )
 
                  shadow_color=self.title_shadow,
                 )
 
-        if self.with_logo:
-            logo = Image.open(get_resource('res/wl-logo-mono.png'))
-            logo = logo.resize((metr.logo_width, logo.size[1] * metr.logo_width / logo.size[0]), Image.ANTIALIAS)
-            alpha = logo.split()[3]
-            alpha = ImageEnhance.Brightness(alpha).enhance(.75)
-            logo.putalpha(alpha)
-            box.skip(metr.logo_top + logo.size[1])
-
         box_img = box.image()
 
         box_img = box.image()
 
-        if self.kind == 'Liryka':
-            # top
+        # Find box position.
+        if self.box_position == 'top':
             box_top = metr.box_top_margin
             box_top = metr.box_top_margin
-        elif self.kind == 'Epika':
-            # bottom
+        elif self.box_position == 'bottom':
             box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
             box_top = metr.height - metr.box_bottom_margin - box_img.size[1]
-        else:
-            # center
+        else:   # Middle.
             box_top = (metr.height - box_img.size[1]) / 2
 
         box_left = metr.bar_width + (metr.width - metr.bar_width -
                         box_img.size[0]) / 2
             box_top = (metr.height - box_img.size[1]) / 2
 
         box_left = metr.bar_width + (metr.width - metr.bar_width -
                         box_img.size[0]) / 2
-        draw.rectangle((box_left, box_top,
+
+        # Draw the white box.
+        ImageDraw.Draw(img).rectangle((box_left, box_top,
             box_left + box_img.size[0], box_top + box_img.size[1]),
             fill='#fff')
             box_left + box_img.size[0], box_top + box_img.size[1]),
             fill='#fff')
+        # Paste the contents into the white box.
         img.paste(box_img, (box_left, box_top), box_img)
         img.paste(box_img, (box_left, box_top), box_img)
+        return img
+
+    def image(self):
+        metr = Metric(self, self.scale)
+        img = Image.new('RGB', (metr.width, metr.height), self.background_color)
+        draw = ImageDraw.Draw(img)
+
+        draw.rectangle((0, 0, metr.bar_width, metr.height), fill=self.bar_color)
+
+        if self.background_img:
+            src = Image.open(self.background_img)
+            trg_size = (metr.width - metr.bar_width, metr.height)
+            if src.size[0] * trg_size[1] < src.size[1] * trg_size[0]:
+                resized = (
+                    trg_size[0],
+                    src.size[1] * trg_size[0] / src.size[0]
+                )
+                cut = (resized[1] - trg_size[1]) / 2
+                src = src.resize(resized, Image.ANTIALIAS)
+                src = src.crop((0, cut, src.size[0], src.size[1] - cut))
+            else:
+                resized = (
+                    src.size[0] * trg_size[1] / src.size[1],
+                    trg_size[1],
+                )
+                cut = (resized[0] - trg_size[0]) / 2
+                src = src.resize(resized, Image.ANTIALIAS)
+                src = src.crop((cut, 0, src.size[0] - cut, src.size[1]))
+
+            img.paste(src, (metr.bar_width, 0))
+            del src
 
 
-        if self.with_logo:
-            img.paste(logo, 
-                (box_left + (box_img.size[0] - logo.size[0]) / 2,
-                    box_top + box_img.size[1] - metr.box_padding_y - logo.size[1]), mask=logo)
+        img = self.add_box(img)
 
         return img
 
 
         return img
 
index a7215a1..12bb24f 100644 (file)
@@ -10,7 +10,7 @@ import re
 from librarian.util import roman_to_int
 
 from librarian import (ValidationError, NoDublinCore, ParseError, DCNS, RDFNS,
 from librarian.util import roman_to_int
 
 from librarian import (ValidationError, NoDublinCore, ParseError, DCNS, RDFNS,
-                       XMLNS, WLURI)
+                       XMLNS, WLURI, WLNS, PLMETNS)
 
 import lxml.etree as etree # ElementTree API using libxml2
 from lxml.etree import XMLSyntaxError
 
 import lxml.etree as etree # ElementTree API using libxml2
 from lxml.etree import XMLSyntaxError
@@ -242,6 +242,9 @@ class WorkInfo(object):
         Field( DCNS('identifier.url'), 'url', WLURI, strict=as_wluri_strict),
         Field( DCNS('rights.license'), 'license', required=False),
         Field( DCNS('rights'), 'license_description'),
         Field( DCNS('identifier.url'), 'url', WLURI, strict=as_wluri_strict),
         Field( DCNS('rights.license'), 'license', required=False),
         Field( DCNS('rights'), 'license_description'),
+
+        Field( PLMETNS('digitisationSponsor'), 'sponsors', multiple=True, default=[]),
+        Field( WLNS('digitisationSponsorNote'), 'sponsor_note', required=False),
     )
 
     @classmethod
     )
 
     @classmethod
@@ -448,6 +451,9 @@ class BookInfo(WorkInfo):
         Field( DCNS('relation.coverImage.url'), 'cover_url', required=False),
         Field( DCNS('relation.coverImage.attribution'), 'cover_by', required=False),
         Field( DCNS('relation.coverImage.source'), 'cover_source', required=False),
         Field( DCNS('relation.coverImage.url'), 'cover_url', required=False),
         Field( DCNS('relation.coverImage.attribution'), 'cover_by', required=False),
         Field( DCNS('relation.coverImage.source'), 'cover_source', required=False),
+        # WLCover-specific.
+        Field( WLNS('coverBarColor'), 'cover_bar_color', required=False),
+        Field( WLNS('coverBoxPosition'), 'cover_box_position', required=False),
     )
 
 
     )
 
 
index 70fc6e5..0eeb76b 100644 (file)
@@ -134,14 +134,17 @@ def extract_fragments(input_filename):
                 fragment = Fragment(id=element.get('fid'), themes=element.text)
 
                 # Append parents
                 fragment = Fragment(id=element.get('fid'), themes=element.text)
 
                 # Append parents
-                if element.getparent().get('id', None) != 'book-text':
-                    parents = [element.getparent()]
-                    while parents[-1].getparent().get('id', None) != 'book-text':
-                        parents.append(parents[-1].getparent())
-
-                    parents.reverse()
-                    for parent in parents:
-                        fragment.append('start', parent)
+                parent = element.getparent()
+                parents = []
+                while parent.get('id', None) != 'book-text':
+                    cparent = copy.deepcopy(parent)
+                    cparent.text = None
+                    parents.append(cparent)
+                    parent = parent.getparent()
+
+                parents.reverse()
+                for parent in parents:
+                    fragment.append('start', parent)
 
                 open_fragments[fragment.id] = fragment
 
 
                 open_fragments[fragment.id] = fragment
 
@@ -177,25 +180,22 @@ def extract_fragments(input_filename):
 
 
 def add_anchor(element, prefix, with_link=True, with_target=True, link_text=None):
 
 
 def add_anchor(element, prefix, with_link=True, with_target=True, link_text=None):
+    parent = element.getparent()
+    index = parent.index(element)
+
     if with_link:
         if link_text is None:
             link_text = prefix
         anchor = etree.Element('a', href='#%s' % prefix)
         anchor.set('class', 'anchor')
         anchor.text = unicode(link_text)
     if with_link:
         if link_text is None:
             link_text = prefix
         anchor = etree.Element('a', href='#%s' % prefix)
         anchor.set('class', 'anchor')
         anchor.text = unicode(link_text)
-        if element.text:
-            anchor.tail = element.text
-            element.text = u''
-        element.insert(0, anchor)
+        parent.insert(index, anchor)
 
     if with_target:
         anchor_target = etree.Element('a', name='%s' % prefix)
         anchor_target.set('class', 'target')
         anchor_target.text = u' '
 
     if with_target:
         anchor_target = etree.Element('a', name='%s' % prefix)
         anchor_target.set('class', 'target')
         anchor_target.text = u' '
-        if element.text:
-            anchor_target.tail = element.text
-            element.text = u''
-        element.insert(0, anchor_target)
+        parent.insert(index, anchor_target)
 
 
 def any_ancestor(element, test):
 
 
 def any_ancestor(element, test):
@@ -225,7 +225,7 @@ def add_anchors(root):
 def raw_printable_text(element):
     working = copy.deepcopy(element)
     for e in working.findall('a'):
 def raw_printable_text(element):
     working = copy.deepcopy(element)
     for e in working.findall('a'):
-        if e.get('class') == 'annotation':
+        if e.get('class') in ('annotation', 'theme-begin'):
             e.text = ''
     return etree.tostring(working, method='text', encoding=unicode).strip()
 
             e.text = ''
     return etree.tostring(working, method='text', encoding=unicode).strip()
 
index 2154985..af258fc 100644 (file)
@@ -28,6 +28,7 @@ from librarian.parser import WLDocument
 from librarian import ParseError, DCNS, get_resource, OutputFile
 from librarian import functions
 from librarian.cover import DefaultEbookCover
 from librarian import ParseError, DCNS, get_resource, OutputFile
 from librarian import functions
 from librarian.cover import DefaultEbookCover
+from .sponsor import sponsor_logo
 
 
 functions.reg_substitute_entities()
 
 
 functions.reg_substitute_entities()
@@ -247,11 +248,23 @@ def transform(wldoc, verbose=False, save_tex=None, morefloats=None,
         style_filename = get_stylesheet("wl2tex")
         style = etree.parse(style_filename)
 
         style_filename = get_stylesheet("wl2tex")
         style = etree.parse(style_filename)
 
-        texml = document.transform(style)
-
         # TeXML -> LaTeX
         temp = mkdtemp('-wl2pdf')
 
         # TeXML -> LaTeX
         temp = mkdtemp('-wl2pdf')
 
+        for sponsor in book_info.sponsors:
+            ins = etree.Element("data-sponsor", name=sponsor)
+            logo = sponsor_logo(sponsor)
+            if logo:
+                fname = 'sponsor-%s' % os.path.basename(logo)
+                shutil.copy(logo, os.path.join(temp, fname))
+                ins.set('src', fname)
+            root.insert(0, ins)
+                
+        if book_info.sponsor_note:
+            root.set("sponsor-note", book_info.sponsor_note)
+
+        texml = document.transform(style)
+
         if cover:
             with open(os.path.join(temp, 'cover.png'), 'w') as f:
                 bound_cover.save(f)
         if cover:
             with open(os.path.join(temp, 'cover.png'), 'w') as f:
                 bound_cover.save(f)
index a9ace8e..8907b08 100644 (file)
@@ -126,6 +126,8 @@ Letters={SmallCaps,UppercaseSmallCaps}
 
 \pagestyle{plain}
 \usepackage{fancyhdr}
 
 \pagestyle{plain}
 \usepackage{fancyhdr}
+\usepackage{marginnote}
+
 
 \makeatletter
 
 
 \makeatletter
 
@@ -238,6 +240,13 @@ Letters={SmallCaps,UppercaseSmallCaps}
     \color{theme}
     \noindent \rule{\linewidth}{0.4pt}
 
     \color{theme}
     \noindent \rule{\linewidth}{0.4pt}
 
+    \ifdefined\sponsors
+        \marginnote{%
+            \centering%
+            \sponsors%
+        }
+    \fi
+
     \rightsinfo
     \vspace{.6em}
 
     \rightsinfo
     \vspace{.6em}
 
index ca948da..c120fb0 100644 (file)
                     \def\funders{Publikację ufundowali i ufundowały:
                         <TeXML escape="1"><xsl:value-of select="@funders" /></TeXML>.}
                 </xsl:if>
                     \def\funders{Publikację ufundowali i ufundowały:
                         <TeXML escape="1"><xsl:value-of select="@funders" /></TeXML>.}
                 </xsl:if>
+
+                <xsl:if test="@sponsor-note|data-sponsor">
+                    \def\sponsors{
+                        \scriptsize
+                        <xsl:choose>
+                            <xsl:when test="@sponsor-note">
+                                <TeXML escape="1"><xsl:value-of select="@sponsor-note" /></TeXML>
+                            </xsl:when>
+                            <xsl:otherwise>
+                                Sfinansowano ze~środków:
+                            </xsl:otherwise>
+                        </xsl:choose>
+
+                        \vspace{1em}
+
+                        <xsl:apply-templates select="data-sponsor" mode="sponsor" />
+                    }
+                </xsl:if>
             </TeXML>
 
             <cmd name="editorialsection" />
             </TeXML>
 
             <cmd name="editorialsection" />
     </xsl:if>
 </xsl:template>
 
     </xsl:if>
 </xsl:template>
 
+<xsl:template match="data-sponsor" mode="sponsor">
+    <cmd name="par"><parm>
+    <xsl:choose>
+        <xsl:when test="@src">
+            \includegraphics[height=0.25\textwidth,width=0.25\textwidth,keepaspectratio]{<xsl:value-of select="@src" />}
+        </xsl:when>
+        <xsl:otherwise>
+            <xsl:value-of select="@name" />
+        </xsl:otherwise>
+    </xsl:choose>
+    </parm></cmd>
+</xsl:template>
 
 <!-- ============== -->
 <!-- = ADDED TAGS = -->
 
 <!-- ============== -->
 <!-- = ADDED TAGS = -->
diff --git a/librarian/res/sponsors/nck.png b/librarian/res/sponsors/nck.png
new file mode 100644 (file)
index 0000000..e53f19c
Binary files /dev/null and b/librarian/res/sponsors/nck.png differ
diff --git a/librarian/res/webtreatsetc-5647576127-ccby.png b/librarian/res/webtreatsetc-5647576127-ccby.png
deleted file mode 100644 (file)
index 6919e93..0000000
Binary files a/librarian/res/webtreatsetc-5647576127-ccby.png and /dev/null differ
diff --git a/librarian/sponsor.py b/librarian/sponsor.py
new file mode 100644 (file)
index 0000000..15d9107
--- /dev/null
@@ -0,0 +1,11 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from librarian import get_resource
+
+def sponsor_logo(name):
+    return {
+        'Narodowe Centrum Kultury': get_resource('res/sponsors/nck.png')
+    }.get(name.strip())
index 9edfa62..37bd7ed 100644 (file)
@@ -45,6 +45,8 @@ def transform(wldoc, flags=None, **options):
     if flags:
         for flag in flags:
             document.edoc.getroot().set(flag, 'yes')
     if flags:
         for flag in flags:
             document.edoc.getroot().set(flag, 'yes')
+    if 'wrapping' in options:
+        options['wrapping'] = str(options['wrapping'])
 
     result = document.transform(style, **options)
 
 
     result = document.transform(style, **options)
 
index 758ab0e..444563c 100755 (executable)
@@ -20,9 +20,6 @@ class Book2Cover(Book2Anything):
                 help='Set width.'),
         Option('-H', '--height', action='store', type='int', dest='height', default=None,
                 help='Set height.'),
                 help='Set width.'),
         Option('-H', '--height', action='store', type='int', dest='height', default=None,
                 help='Set height.'),
-        Option('-l', '--with-logo', dest='with_logo',
-                action='store_true', default=False,
-                help='Add WL logo in white box.'),
     ]
 
     @staticmethod
     ]
 
     @staticmethod
index 5d48eec..2c1d04e 100755 (executable)
@@ -17,7 +17,7 @@ class Book2Html(Book2Anything):
                 action='store_false', default=True,
                 help='output raw text for use in templates')
     ]
                 action='store_false', default=True,
                 help='output raw text for use in templates')
     ]
-    parser_args = [
+    parser_options = [
         Option('-i', '--ignore-dublin-core', dest='parse_dublincore', 
                 action='store_false', default=True,
                 help='don\'t try to parse dublin core metadata')
         Option('-i', '--ignore-dublin-core', dest='parse_dublincore', 
                 action='store_false', default=True,
                 help='don\'t try to parse dublin core metadata')
index 68e2d08..ccb5fac 100755 (executable)
@@ -12,7 +12,7 @@ class Book2Pdf(Book2Anything):
     ext = "pdf"
     uses_cover = True
     uses_provider = True
     ext = "pdf"
     uses_cover = True
     uses_provider = True
-    transform_args = [
+    transform_options = [
         Option('-t', '--save-tex', dest='save_tex', metavar='FILE',
                 help='path to save the intermediary LaTeX file to'),
         Option('-m', '--morefloats', dest='morefloats', metavar='old/new/none',
         Option('-t', '--save-tex', dest='save_tex', metavar='FILE',
                 help='path to save the intermediary LaTeX file to'),
         Option('-m', '--morefloats', dest='morefloats', metavar='old/new/none',
index 1b4c0ef..c706a07 100755 (executable)
@@ -13,15 +13,20 @@ class Book2Txt(Book2Anything):
     ext = "txt"
     uses_cover = False
     uses_provider = False
     ext = "txt"
     uses_cover = False
     uses_provider = False
-    parser_args = [
+    parser_options = [
         Option('-i', '--ignore-dublin-core', dest='parse_dublincore', 
                 action='store_false', default=True,
                 help='don\'t try to parse dublin core metadata')
     ]
         Option('-i', '--ignore-dublin-core', dest='parse_dublincore', 
                 action='store_false', default=True,
                 help='don\'t try to parse dublin core metadata')
     ]
-    transform_args = [
+    transform_options = [
         Option('-w', '--wrap', action='store', type='int', dest='wrapping', default=0,
                 help='set line wrap column')
     ]
         Option('-w', '--wrap', action='store', type='int', dest='wrapping', default=0,
                 help='set line wrap column')
     ]
+    transform_flags = [
+        Option('-r', '--raw', dest='raw-text', 
+                action='store_true', default=False,
+                help='Produce raw text, without any surrounding info.')
+    ]
     transform = WLDocument.as_text
 
 
     transform = WLDocument.as_text
 
 
index 7bcbbc2..732f145 100755 (executable)
--- a/setup.py
+++ b/setup.py
@@ -29,7 +29,8 @@ setup(
     maintainer_email='radoslaw.czajka@nowoczesnapolska.org.pl',
     url='http://github.com/fnp/librarian',
     packages=['librarian'],
     maintainer_email='radoslaw.czajka@nowoczesnapolska.org.pl',
     url='http://github.com/fnp/librarian',
     packages=['librarian'],
-    package_data={'librarian': ['xslt/*.xslt', 'epub/*', 'mobi/*', 'pdf/*', 'fb2/*', 'fonts/*', 'res/*'] +
+    package_data={'librarian': ['xslt/*.xslt', 'epub/*', 'mobi/*', 'pdf/*', 'fb2/*', 'fonts/*'] +
+                                whole_tree(os.path.join(os.path.dirname(__file__), 'librarian'), 'res') +
                                 whole_tree(os.path.join(os.path.dirname(__file__), 'librarian'), 'font-optimizer')},
     include_package_data=True,
     install_requires=[
                                 whole_tree(os.path.join(os.path.dirname(__file__), 'librarian'), 'font-optimizer')},
     include_package_data=True,
     install_requires=[
index fd18174..24285f1 100644 (file)
@@ -6,32 +6,33 @@
 <div id="themes"><ol>
 <li>Miłość platoniczna: <a href="#m1189062500041">1</a> <a href="#m1189062500041">2</a> </li>
 <li>Natura: <a href="#m1189062528872">1</a> </li>
 <div id="themes"><ol>
 <li>Miłość platoniczna: <a href="#m1189062500041">1</a> <a href="#m1189062500041">2</a> </li>
 <li>Natura: <a href="#m1189062528872">1</a> </li>
+<li>Nicość: <a href="#m1">1</a> </li>
 </ol></div>
 <h1>
 <span class="author">Adam Asnyk</span><span class="title"><a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a>Między nami nic nie było</span>
 </h1>
 <a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a><div class="stanza">
 </ol></div>
 <h1>
 <span class="author">Adam Asnyk</span><span class="title"><a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a>Między nami nic nie było</span>
 </h1>
 <a name="m1189062500041" class="theme-begin" fid="1189062500041">Miłość platoniczna</a><div class="stanza">
-<a name="sec4"></a><p class="verse"><a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a>Między nami nic nie było!</p>
+<a name="sec4"></a><a name="f1" class="target"> </a><a href="#f1" class="anchor">1</a><p class="verse">Między nami <a name="m1" class="theme-begin" fid="1">Nicość</a>nic nie było!<span class="theme-end" fid="1"></span></p>
 <p class="verse">Żadnych zwierzeń, wyznań żadnych!</p>
 <p class="verse">Nic nas z sobą nie łączyło —</p>
 <p class="verse">Prócz wiosennych marzeń zdradnych;</p>
 </div>
 <div class="stanza">
 <p class="verse">Żadnych zwierzeń, wyznań żadnych!</p>
 <p class="verse">Nic nas z sobą nie łączyło —</p>
 <p class="verse">Prócz wiosennych marzeń zdradnych;</p>
 </div>
 <div class="stanza">
-<a name="sec5"></a><p class="verse"><a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a><a name="m1189062528872" class="theme-begin" fid="1189062528872">Natura</a>Prócz tych woni, barw i blasków,</p>
+<a name="sec5"></a><a name="f5" class="target"> </a><a href="#f5" class="anchor">5</a><p class="verse"><a name="m1189062528872" class="theme-begin" fid="1189062528872">Natura</a>Prócz tych woni, barw i blasków,</p>
 <p class="verse">Unoszących się w przestrzeni;</p>
 <p class="verse">Prócz szumiących śpiewem lasków</p>
 <p class="verse">I tej świeżej łąk zieleni;</p>
 </div>
 <div class="stanza">
 <a name="sec6"></a><p class="verse">Prócz tych kaskad i potoków,</p>
 <p class="verse">Unoszących się w przestrzeni;</p>
 <p class="verse">Prócz szumiących śpiewem lasków</p>
 <p class="verse">I tej świeżej łąk zieleni;</p>
 </div>
 <div class="stanza">
 <a name="sec6"></a><p class="verse">Prócz tych kaskad i potoków,</p>
-<p class="verse"><a name="f10" class="target"> </a><a href="#f10" class="anchor">10</a>Zraszających każdy parów,</p>
+<a name="f10" class="target"> </a><a href="#f10" class="anchor">10</a><p class="verse">Zraszających każdy parów,</p>
 <p class="verse">Prócz girlandy tęcz, obłoków,</p>
 <p class="verse">Prócz natury słodkich czarów;</p>
 </div>
 <div class="stanza">
 <a name="sec7"></a><p class="verse">Prócz tych wspólnych, jasnych zdrojów,</p>
 <p class="verse">Z których serce zachwyt piło;</p>
 <p class="verse">Prócz girlandy tęcz, obłoków,</p>
 <p class="verse">Prócz natury słodkich czarów;</p>
 </div>
 <div class="stanza">
 <a name="sec7"></a><p class="verse">Prócz tych wspólnych, jasnych zdrojów,</p>
 <p class="verse">Z których serce zachwyt piło;</p>
-<p class="verse"><a name="f15" class="target"> </a><a href="#f15" class="anchor">15</a>Prócz pierwiosnków i powojów,—</p>
+<a name="f15" class="target"> </a><a href="#f15" class="anchor">15</a><p class="verse">Prócz pierwiosnków i powojów,—</p>
 <p class="verse">Między nami nic nie było!<span class="theme-end" fid="1189062528872"></span><span class="theme-end" fid="1189062500041"></span></p>
 </div>
 </div>
 <p class="verse">Między nami nic nie było!<span class="theme-end" fid="1189062528872"></span><span class="theme-end" fid="1189062500041"></span></p>
 </div>
 </div>
diff --git a/tests/files/text/asnyk_miedzy_nami_fragments.html b/tests/files/text/asnyk_miedzy_nami_fragments.html
new file mode 100644 (file)
index 0000000..944d830
--- /dev/null
@@ -0,0 +1,50 @@
+1: Nicość
+<div class="stanza"><p class="verse">nic nie było!</p>
+</div>
+
+
+1189062500041: Miłość platoniczna
+<div class="stanza">
+<p class="verse">Między nami nic nie było!</p>
+<p class="verse">Żadnych zwierzeń, wyznań żadnych!</p>
+<p class="verse">Nic nas z sobą nie łączyło —</p>
+<p class="verse">Prócz wiosennych marzeń zdradnych;</p>
+</div>
+<div class="stanza">
+<p class="verse">Prócz tych woni, barw i blasków,</p>
+<p class="verse">Unoszących się w przestrzeni;</p>
+<p class="verse">Prócz szumiących śpiewem lasków</p>
+<p class="verse">I tej świeżej łąk zieleni;</p>
+</div>
+<div class="stanza">
+<p class="verse">Prócz tych kaskad i potoków,</p>
+<p class="verse">Zraszających każdy parów,</p>
+<p class="verse">Prócz girlandy tęcz, obłoków,</p>
+<p class="verse">Prócz natury słodkich czarów;</p>
+</div>
+<div class="stanza">
+<p class="verse">Prócz tych wspólnych, jasnych zdrojów,</p>
+<p class="verse">Z których serce zachwyt piło;</p>
+<p class="verse">Prócz pierwiosnków i powojów,—</p>
+<p class="verse">Między nami nic nie było!</p>
+</div>
+
+
+1189062528872: Natura
+<div class="stanza"><p class="verse">Prócz tych woni, barw i blasków,</p>
+<p class="verse">Unoszących się w przestrzeni;</p>
+<p class="verse">Prócz szumiących śpiewem lasków</p>
+<p class="verse">I tej świeżej łąk zieleni;</p>
+</div>
+<div class="stanza">
+<p class="verse">Prócz tych kaskad i potoków,</p>
+<p class="verse">Zraszających każdy parów,</p>
+<p class="verse">Prócz girlandy tęcz, obłoków,</p>
+<p class="verse">Prócz natury słodkich czarów;</p>
+</div>
+<div class="stanza">
+<p class="verse">Prócz tych wspólnych, jasnych zdrojów,</p>
+<p class="verse">Z których serce zachwyt piło;</p>
+<p class="verse">Prócz pierwiosnków i powojów,—</p>
+<p class="verse">Między nami nic nie było!</p>
+</div>
old mode 100755 (executable)
new mode 100644 (file)
old mode 100755 (executable)
new mode 100644 (file)
index a94b8f0..8036fce 100644 (file)
@@ -37,7 +37,7 @@
 
 
 
 
 
 
-<strofa>Między nami nic nie było!/
+<strofa>Między nami <begin id="b1"/><motyw id="m1">Nicość</motyw>nic nie było!<end id="e1"/>/
 Żadnych zwierzeń, wyznań żadnych!/
 Nic nas z sobą nie łączyło ---/
 Prócz wiosennych marzeń zdradnych;</strofa>
 Żadnych zwierzeń, wyznań żadnych!/
 Nic nas z sobą nie łączyło ---/
 Prócz wiosennych marzeń zdradnych;</strofa>
diff --git a/tests/test_html_fragments.py b/tests/test_html_fragments.py
new file mode 100644 (file)
index 0000000..99bb62d
--- /dev/null
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+#
+# This file is part of Librarian, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+#
+from librarian.html import extract_fragments
+from nose.tools import *
+from utils import get_fixture
+
+
+def test_fragments():
+    expected_output_file_path = get_fixture('text', 'asnyk_miedzy_nami_fragments.html')
+
+    closed_fragments, open_fragments = extract_fragments(
+        get_fixture('text', 'asnyk_miedzy_nami_expected.html'))
+    assert not open_fragments
+    fragments_text = u"\n\n".join(u"%s: %s\n%s" % (f.id, f.themes, f)
+                                    for f in closed_fragments.values())
+    assert_equal(fragments_text, file(expected_output_file_path).read().decode('utf-8'))
+