]> git.scottworley.com Git - paperdoorknob/commitdiff
Reify Layout
authorScott Worley <scottworley@scottworley.com>
Wed, 20 Dec 2023 23:42:32 +0000 (15:42 -0800)
committerScott Worley <scottworley@scottworley.com>
Wed, 20 Dec 2023 23:42:32 +0000 (15:42 -0800)
args.py
glowfic.py
paperdoorknob.py
paperdoorknob_test.py
spec.py
testdata/this-is-glowfic.html

diff --git a/args.py b/args.py
index f966ba92ddcd0d6f2044556d9323d2508c296f43..62b9404e93479dfdf0f456c88e144bf5edc83d14 100644 (file)
--- a/args.py
+++ b/args.py
@@ -15,6 +15,7 @@ from xdg_base_dirs import xdg_cache_home
 
 from domfilter import ApplyDOMFilters, DOMFilters
 from fetch import CachingFetcher
 
 from domfilter import ApplyDOMFilters, DOMFilters
 from fetch import CachingFetcher
+from glowfic import BelowIconLayout
 from htmlfilter import ApplyHTMLFilters, HTMLFilters
 from images import DiskImageStore
 from spec import Spec
 from htmlfilter import ApplyHTMLFilters, HTMLFilters
 from images import DiskImageStore
 from spec import Spec
@@ -62,6 +63,7 @@ See https://faculty.bard.edu/bloch/geometry.pdf for details
 @contextmanager
 def spec_from_commandline_args() -> Iterator[Spec]:
     args = _command_line_parser().parse_args()
 @contextmanager
 def spec_from_commandline_args() -> Iterator[Spec]:
     args = _command_line_parser().parse_args()
+    texifier = PandocTexifier(args.pandoc or 'pandoc')
     with CachingFetcher(args.cache_path, args.timeout) as fetcher:
         with open(args.out + '.tex', 'wb') as texout:
             yield Spec(
     with CachingFetcher(args.cache_path, args.timeout) as fetcher:
         with open(args.out + '.tex', 'wb') as texout:
             yield Spec(
@@ -70,6 +72,6 @@ def spec_from_commandline_args() -> Iterator[Spec]:
                 DiskImageStore(args.out + '_images', fetcher),
                 lambda x: ApplyHTMLFilters(args.htmlfilters, x),
                 lambda x: ApplyDOMFilters(args.domfilters, x),
                 DiskImageStore(args.out + '_images', fetcher),
                 lambda x: ApplyHTMLFilters(args.htmlfilters, x),
                 lambda x: ApplyDOMFilters(args.domfilters, x),
-                PandocTexifier(args.pandoc or 'pandoc'),
+                BelowIconLayout(texifier),
                 args.geometry,
                 texout)
                 args.geometry,
                 texout)
index 41697867b2453e0af35175de866f02fe71409c54..0eab425d863dadb8669468af9ebc49a87527f19b 100644 (file)
@@ -5,6 +5,7 @@
 # Free Software Foundation, version 3.
 
 
 # Free Software Foundation, version 3.
 
 
+from abc import ABC, abstractmethod
 from dataclasses import dataclass
 import itertools
 
 from dataclasses import dataclass
 import itertools
 
@@ -14,6 +15,7 @@ from bs4 import BeautifulSoup
 from bs4.element import Tag
 
 from images import ImageStore
 from bs4.element import Tag
 
 from images import ImageStore
+from texify import Texifier
 
 
 @dataclass(frozen=True)
 
 
 @dataclass(frozen=True)
@@ -77,3 +79,47 @@ def makeChunk(chunk_dom: Tag, image_store: ImageStore) -> Chunk:
                  getTextByClass('post-screenname'),
                  getTextByClass('post-author'),
                  content)
                  getTextByClass('post-screenname'),
                  getTextByClass('post-author'),
                  content)
+
+
+def renderIcon(icon_path: str | None) -> bytes:
+    return b'\\includegraphics{%s}' % icon_path.encode(
+        'UTF-8') if icon_path else b''
+
+
+class Layout(ABC):
+
+    @abstractmethod
+    def renderChunk(self, chunk: Chunk) -> bytes:
+        raise NotImplementedError()
+
+
+class ContentOnlyLayout(Layout):
+
+    def __init__(self, texifier: Texifier) -> None:
+        self._texifier = texifier
+
+    def renderChunk(self, chunk: Chunk) -> bytes:
+        return self._texifier.texify(chunk.content)
+
+
+class BelowIconLayout(Layout):
+
+    def __init__(self, texifier: Texifier) -> None:
+        self._texifier = texifier
+
+    def renderChunk(self, chunk: Chunk) -> bytes:
+        icon_width = b'0.25\\textwidth'  # TODO: Make this configurable
+        return b'''\\begin{wrapfigure}{l}{%s}
+%s
+%s
+%s
+%s
+\\end{wrapfigure}
+%s
+''' % (
+            icon_width,
+            renderIcon(chunk.icon),
+            chunk.character.encode('UTF-8') if chunk.character else b'',
+            chunk.screen_name.encode('UTF-8') if chunk.screen_name else b'',
+            chunk.author.encode('UTF-8') if chunk.author else b'',
+            self._texifier.texify(chunk.content))
index 160f0db769416c6cd034486d8dcb513b756e8cdd..f8b336194974668477b5739b74c014a00d7e7549 100644 (file)
@@ -8,7 +8,7 @@
 from bs4 import BeautifulSoup
 
 from args import spec_from_commandline_args
 from bs4 import BeautifulSoup
 
 from args import spec_from_commandline_args
-from glowfic import chunkDOMs
+from glowfic import chunkDOMs, makeChunk
 from spec import Spec
 
 
 from spec import Spec
 
 
@@ -17,7 +17,10 @@ def parse(content: bytes) -> BeautifulSoup:
 
 
 def process(spec: Spec) -> None:
 
 
 def process(spec: Spec) -> None:
-    spec.texout.write(b'\\documentclass{article}\n\\usepackage{wrapfig}\n')
+    spec.texout.write(b'''\\documentclass{article}
+\\usepackage{graphicx}
+\\usepackage{wrapfig}
+''')
     if spec.geometry is not None:
         spec.texout.write(b'\\usepackage[' +
                           spec.geometry.encode('UTF-8') +
     if spec.geometry is not None:
         spec.texout.write(b'\\usepackage[' +
                           spec.geometry.encode('UTF-8') +
@@ -26,7 +29,8 @@ def process(spec: Spec) -> None:
     html = parse(spec.htmlfilter(spec.fetcher.fetch(spec.url)))
     for r in chunkDOMs(html):
         spec.domfilter(r)
     html = parse(spec.htmlfilter(spec.fetcher.fetch(spec.url)))
     for r in chunkDOMs(html):
         spec.domfilter(r)
-        spec.texout.write(spec.texifier.texify(r))
+        chunk = makeChunk(r, spec.images)
+        spec.texout.write(spec.layout.renderChunk(chunk))
     spec.texout.write(b'\\end{document}\n')
 
 
     spec.texout.write(b'\\end{document}\n')
 
 
index 4291bb4e613659b29ec21eecd77c60777f6e97a6..c1f8b60a85a3bc3788d7c0c002183e85ff76ba63 100644 (file)
@@ -15,6 +15,7 @@ import paperdoorknob
 from testing.fakeserver import FakeGlowficServer
 from domfilter import ApplyDOMFilters
 from fetch import DirectFetcher, FakeFetcher, Fetcher
 from testing.fakeserver import FakeGlowficServer
 from domfilter import ApplyDOMFilters
 from fetch import DirectFetcher, FakeFetcher, Fetcher
+from glowfic import ContentOnlyLayout, BelowIconLayout
 from images import FakeImageStore
 from spec import Spec
 from texify import DirectTexifier, PandocTexifier, VerifyingTexifier
 from images import FakeImageStore
 from spec import Spec
 from texify import DirectTexifier, PandocTexifier, VerifyingTexifier
@@ -40,11 +41,12 @@ class BaseTestProcess(ABC):
             FakeImageStore(),
             lambda x: x,
             lambda x: ApplyDOMFilters('NoEdit,NoFooter', x),
             FakeImageStore(),
             lambda x: x,
             lambda x: ApplyDOMFilters('NoEdit,NoFooter', x),
-            PandocTexifier('pandoc'),
+            ContentOnlyLayout(PandocTexifier('pandoc')),
             'margin=20mm',
             buf)
         paperdoorknob.process(spec)
         assert buf.getvalue() == b'''\\documentclass{article}
             'margin=20mm',
             buf)
         paperdoorknob.process(spec)
         assert buf.getvalue() == b'''\\documentclass{article}
+\\usepackage{graphicx}
 \\usepackage{wrapfig}
 \\usepackage[margin=20mm]{geometry}
 \\begin{document}
 \\usepackage{wrapfig}
 \\usepackage[margin=20mm]{geometry}
 \\begin{document}
@@ -64,7 +66,7 @@ Pretty sure.
             FakeImageStore(),
             lambda x: x,
             lambda x: ApplyDOMFilters('NoEdit,NoFooter', x),
             FakeImageStore(),
             lambda x: x,
             lambda x: ApplyDOMFilters('NoEdit,NoFooter', x),
-            texifier,
+            ContentOnlyLayout(texifier),
             None,
             buf)
         paperdoorknob.process(spec)
             None,
             buf)
         paperdoorknob.process(spec)
@@ -77,7 +79,7 @@ Pretty sure.
                 FakeImageStore(),
                 lambda x: x,
                 lambda x: ApplyDOMFilters('NoEdit,NoFooter', x),
                 FakeImageStore(),
                 lambda x: x,
                 lambda x: ApplyDOMFilters('NoEdit,NoFooter', x),
-                PandocTexifier('pandoc'),
+                BelowIconLayout(PandocTexifier('pandoc')),
                 None,
                 out)
             paperdoorknob.process(spec)
                 None,
                 out)
             paperdoorknob.process(spec)
diff --git a/spec.py b/spec.py
index 2b80f163d880c78d36556437b70ab4805eed8a48..34e2e6b3593bf34a7ec773c20ac6a08de67d8797 100644 (file)
--- a/spec.py
+++ b/spec.py
@@ -12,7 +12,7 @@ from typing import Callable, IO
 from bs4.element import Tag
 
 from fetch import Fetcher
 from bs4.element import Tag
 
 from fetch import Fetcher
-from texify import Texifier
+from glowfic import Layout
 from images import ImageStore
 
 
 from images import ImageStore
 
 
@@ -24,6 +24,6 @@ class Spec:
     images: ImageStore
     htmlfilter: Callable[[bytes], bytes]
     domfilter: Callable[[Tag], None]
     images: ImageStore
     htmlfilter: Callable[[bytes], bytes]
     domfilter: Callable[[Tag], None]
-    texifier: Texifier
+    layout: Layout
     geometry: str | None
     texout: IO[bytes]
     geometry: str | None
     texout: IO[bytes]
index 22c7a3730d9d965542662883b0bb9624423a29ac..207cdd187f3630508952332b270e27874114124f 100644 (file)
@@ -2,17 +2,17 @@
   <body>
     <div class="post-container post-post">
       <div class="post-edit-box">We don't want edit boxes</div>
   <body>
     <div class="post-container post-post">
       <div class="post-edit-box">We don't want edit boxes</div>
-      This is glowfic
+      <div class="post-content">This is glowfic</div>
       <div class="post-footer">We don't want footers</div>
     </div>
     <div class="flat-post-replies">
       <div class="post-container post-reply">
         <div class="post-edit-box">We don't want edit boxes</div>
       <div class="post-footer">We don't want footers</div>
     </div>
     <div class="flat-post-replies">
       <div class="post-container post-reply">
         <div class="post-edit-box">We don't want edit boxes</div>
-        You <em>sure</em>?
+        <div class="post-content">You <em>sure</em>?</div>
         <div class="post-footer">We don't want footers</div>
       </div>
       <div class="post-container post-reply">
         <div class="post-footer">We don't want footers</div>
       </div>
       <div class="post-container post-reply">
-        Pretty sure.
+        <div class="post-content">Pretty sure.</div>
       </div>
     </div>
   </body>
       </div>
     </div>
   </body>